[{"data":1,"prerenderedAt":671},["ShallowReactive",2],{"Categories":3,"NavIndexCategoriesCountFooter":203,"content-\u002F2020\u002F04\u002F01\u002Fobservable-account\u002F":204},[4,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,68,70,71,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202],{"category":5},"System Administration",{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":27},"Software Development",{"category":5},{"category":5},{"category":5},{"category":5},{"category":27},{"category":27},{"category":5},{"category":5},{"category":5},{"category":27},{"category":5},{"category":5},{"category":5},{"category":27},{"category":27},{"category":27},{"category":27},{"category":5},{"category":5},{"category":5},{"category":27},{"category":27},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":5},{"category":27},{"category":5},{"category":5},{"category":27},{"category":27},{"category":27},{"category":27},{"category":5},{"category":27},{"category":27},{"category":67},"Drones & RC",{"category":69},"DIY Projects",{"category":67},{"category":72},"Photography",{"category":69},{"category":69},{"category":69},{"category":67},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":69},{"category":67},{"category":69},{"category":69},{"category":67},{"category":67},{"category":72},{"category":72},{"category":72},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":5},{"category":5},{"category":72},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":5},{"category":67},{"category":67},{"category":72},{"category":72},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":67},{"category":72},{"category":67},{"category":138},"3D Printing - Laser Cutting - CNC",{"category":138},{"category":138},{"category":138},{"category":138},{"category":138},{"category":138},{"category":138},{"category":138},{"category":138},{"category":138},{"category":138},{"category":5},{"category":138},{"category":27},{"category":27},{"category":138},{"category":138},{"category":72},{"category":158},"Photography,3D Printing - Laser Cutting - CNC",{"category":27},{"category":27},{"category":69},{"category":27},{"category":27},{"category":27},{"category":27},{"category":5},{"category":67},{"category":5},{"category":5},{"category":27},{"category":27},{"category":27},{"category":27},{"category":27},{"category":69},{"category":27},{"category":27},{"category":27},{"category":27},{"category":181},"Home Assistant",{"category":181},{"category":72},{"category":27},{"category":27},{"category":72},{"category":138},{"category":5},{"category":72},{"category":72},{"category":138},{"category":27},{"category":181},{"category":181},{"category":72},{"category":72},{"category":72},{"category":72},{"category":72},{"category":72},{"category":72},{"category":72},191,{"id":205,"title":206,"body":207,"category":655,"date":656,"description":213,"embedImage":655,"extension":657,"image":655,"intro":213,"meta":658,"navigation":659,"path":660,"seo":661,"series":662,"sitemap":663,"stem":664,"tags":665,"__hash__":670},"content\u002F2020\u002F04\u002F01\u002Fobservable-account.md","Observable account",{"type":208,"value":209,"toc":649},"minimark",[210,214,217,220,225,228,231,233,237,240,260,263,320,323,360,363,382,386,392,395,403,406,487,490,609,615,622,624,628,631,633,645],[211,212,213],"p",{},"So far we are showing the account balances - and the next step is really to sort out the transaction view.",[211,215,216],{},"But - before we do that - let's sort out the nested callbacks we currently have.",[218,219],"hr",{},[221,222,224],"h2",{"id":223},"callbacks","Callbacks",[211,226,227],{},"These work - but - nesting them makes the code harder to follow.",[211,229,230],{},"Let's make the account handling use the built in ObservableObject handling - so that when the account changes the view notices this. We can then write a simplified refresh method that will also allow us to refresh the transactions when we add them.",[218,232],{},[221,234,236],{"id":235},"make-account-service-observable","Make Account Service observable",[211,238,239],{},"We need to make some changes to the account service.",[241,242,243,251,257],"ul",{},[244,245,246,247],"li",{},"it needs to implement ",[248,249,250],"code",{},"ObservableObject",[244,252,253,254],{},"it needs to have a variable that is annotated as ",[248,255,256],{},"@Published",[244,258,259],{},"the method is no longer static, no longer gets callbacks (and we'll rename it refresh)",[211,261,262],{},"Change the class definition to start:",[264,265,270],"pre",{"className":266,"code":267,"language":268,"meta":269,"style":269},"language-swift shiki shiki-themes github-dark","class AccountService : ObservableObject {\n    @Published public var account : Account? = nil\n","swift","",[248,271,272,295],{"__ignoreMap":269},[273,274,277,281,285,289,292],"span",{"class":275,"line":276},"line",1,[273,278,280],{"class":279},"snl16","class",[273,282,284],{"class":283},"svObZ"," AccountService",[273,286,288],{"class":287},"s95oV"," : ",[273,290,291],{"class":283},"ObservableObject ",[273,293,294],{"class":287},"{\n",[273,296,298,301,304,307,310,313,316],{"class":275,"line":297},2,[273,299,300],{"class":279},"    @Published",[273,302,303],{"class":279}," public",[273,305,306],{"class":279}," var",[273,308,309],{"class":287}," account : Account",[273,311,312],{"class":279},"?",[273,314,315],{"class":279}," =",[273,317,319],{"class":318},"sDLfK"," nil\n",[211,321,322],{},"Change the method signature to:",[264,324,326],{"className":266,"code":325,"language":268,"meta":269,"style":269},"public func refresh(token: String, config: Config)\n",[248,327,328],{"__ignoreMap":269},[273,329,330,333,336,339,342,345,348,351,354,357],{"class":275,"line":276},[273,331,332],{"class":279},"public",[273,334,335],{"class":279}," func",[273,337,338],{"class":283}," refresh",[273,340,341],{"class":287},"(",[273,343,344],{"class":283},"token",[273,346,347],{"class":287},": ",[273,349,350],{"class":318},"String",[273,352,353],{"class":287},", ",[273,355,356],{"class":283},"config",[273,358,359],{"class":287},": Config)\n",[211,361,362],{},"Remove all calls to callback in the method and at the end if we made it that far we set:",[264,364,366],{"className":266,"code":365,"language":268,"meta":269,"style":269},"self.account = account\n",[248,367,368],{"__ignoreMap":269},[273,369,370,373,376,379],{"class":275,"line":276},[273,371,372],{"class":318},"self",[273,374,375],{"class":287},".account ",[273,377,378],{"class":279},"=",[273,380,381],{"class":287}," account\n",[221,383,385],{"id":384},"content-view","Content View",[211,387,388,389,391],{},"We now want to listen to changes to the service - the view will be notified that a change has happened when the ",[248,390,256],{}," variable changes.",[211,393,394],{},"In the content view remove the state variable for account and add",[264,396,401],{"className":397,"code":399,"language":400},[398],"language-text","@ObservedObject var accountService = AccountService()\n","text",[248,402,399],{"__ignoreMap":269},[211,404,405],{},"In the view heirarchy - where we have the AccountView - let's use the service variable when present:",[264,407,409],{"className":266,"code":408,"language":268,"meta":269,"style":269},"if (accountService.account != nil) {\n    AccountView(account: accountService.account!)\n        .navigationBarTitle(Text(accountService.account!.name), displayMode: .inline)\n    }\n}\n",[248,410,411,428,447,475,481],{"__ignoreMap":269},[273,412,413,416,419,422,425],{"class":275,"line":276},[273,414,415],{"class":279},"if",[273,417,418],{"class":287}," (accountService.account ",[273,420,421],{"class":279},"!=",[273,423,424],{"class":318}," nil",[273,426,427],{"class":287},") {\n",[273,429,430,433,435,438,441,444],{"class":275,"line":297},[273,431,432],{"class":318},"    AccountView",[273,434,341],{"class":287},[273,436,437],{"class":318},"account",[273,439,440],{"class":287},": accountService.account",[273,442,443],{"class":279},"!",[273,445,446],{"class":287},")\n",[273,448,450,453,456,458,461,464,466,469,472],{"class":275,"line":449},3,[273,451,452],{"class":287},"        .",[273,454,455],{"class":318},"navigationBarTitle",[273,457,341],{"class":287},[273,459,460],{"class":318},"Text",[273,462,463],{"class":287},"(accountService.account",[273,465,443],{"class":279},[273,467,468],{"class":287},".name), ",[273,470,471],{"class":318},"displayMode",[273,473,474],{"class":287},": .inline)\n",[273,476,478],{"class":275,"line":477},4,[273,479,480],{"class":287},"    }\n",[273,482,484],{"class":275,"line":483},5,[273,485,486],{"class":287},"}\n",[211,488,489],{},"Replace the entire getToken method (which since the last change is badly named too) with a refresh method:",[264,491,493],{"className":266,"code":492,"language":268,"meta":269,"style":269},"func refresh() {\n    if let config = self.config {\n        TokenService.getToken(config: config) { (accessToken) in\n            if let token = accessToken {\n                self.accountService.refresh(token: token, config: config)\n                \u002F\u002F We will add transaction refresh here later on\n            }\n        }\n    }\n}\n",[248,494,495,505,524,542,557,580,587,593,599,604],{"__ignoreMap":269},[273,496,497,500,502],{"class":275,"line":276},[273,498,499],{"class":279},"func",[273,501,338],{"class":283},[273,503,504],{"class":287},"() {\n",[273,506,507,510,513,516,518,521],{"class":275,"line":297},[273,508,509],{"class":279},"    if",[273,511,512],{"class":279}," let",[273,514,515],{"class":287}," config ",[273,517,378],{"class":279},[273,519,520],{"class":318}," self",[273,522,523],{"class":287},".config {\n",[273,525,526,529,532,534,536,539],{"class":275,"line":449},[273,527,528],{"class":287},"        TokenService.",[273,530,531],{"class":318},"getToken",[273,533,341],{"class":287},[273,535,356],{"class":318},[273,537,538],{"class":287},": config) { (accessToken) ",[273,540,541],{"class":279},"in\n",[273,543,544,547,549,552,554],{"class":275,"line":477},[273,545,546],{"class":279},"            if",[273,548,512],{"class":279},[273,550,551],{"class":287}," token ",[273,553,378],{"class":279},[273,555,556],{"class":287}," accessToken {\n",[273,558,559,562,565,568,570,572,575,577],{"class":275,"line":483},[273,560,561],{"class":318},"                self",[273,563,564],{"class":287},".accountService.",[273,566,567],{"class":318},"refresh",[273,569,341],{"class":287},[273,571,344],{"class":318},[273,573,574],{"class":287},": token, ",[273,576,356],{"class":318},[273,578,579],{"class":287},": config)\n",[273,581,583],{"class":275,"line":582},6,[273,584,586],{"class":585},"sAwPA","                \u002F\u002F We will add transaction refresh here later on\n",[273,588,590],{"class":275,"line":589},7,[273,591,592],{"class":287},"            }\n",[273,594,596],{"class":275,"line":595},8,[273,597,598],{"class":287},"        }\n",[273,600,602],{"class":275,"line":601},9,[273,603,480],{"class":287},[273,605,607],{"class":275,"line":606},10,[273,608,486],{"class":287},[211,610,611,612],{},"In the .OK state of askForAuth - call ",[248,613,614],{},"self.refresh()",[211,616,617,618,621],{},"If you want you can also add another naviagtionBarItem with a suitable icon (",[248,619,620],{},"Image(systemName: \"arrow.clockwise\")"," perhaps) that calls refresh().",[218,623],{},[221,625,627],{"id":626},"summary","Summary",[211,629,630],{},"We've updated the app so that the view stack watches for changes to the account. This will make it easier to add the transaction views later on.",[218,632],{},[211,634,635],{},[636,637,644],"a",{"href":638,"rel":639,"target":643},"https:\u002F\u002Fgithub.com\u002Fchrissearle\u002Flommepenger-swiftui",[640,641,642],"nofollow","noopener","noreferer","_blank","GitHub Repository",[646,647,648],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":269,"searchDepth":297,"depth":297,"links":650},[651,652,653,654],{"id":223,"depth":297,"text":224},{"id":235,"depth":297,"text":236},{"id":384,"depth":297,"text":385},{"id":626,"depth":297,"text":627},null,"2020-04-01 08:15 +0200","md",{},true,"\u002F2020\u002F04\u002F01\u002Fobservable-account",{"title":206,"description":213},"Revisiting the Sbanken API with SwiftUI",{"loc":660},"2020\u002F04\u002F01\u002Fobservable-account",[666,268,667,668,669],"ios","swiftui","xcode","sbanken","-P3Vy5zEuF_e3DkMmeWRzERCM8Hl6qaj5jCiP5-DHss",1775293006974]