Refreshing view after api call in OnOpenUrl view modifier

Viewed 440

I have this very basic piece of code in one of my Views:

.onOpenURL(perform: { url in
                avm.handleRedirect(viewContext,url: url)        })

where avm is defined as

@ObservedObject var avm = AccountsViewModel.makeAccountsViewModel()

avm has this basic property:

@Published var isLoading = true

That when set, my view listens to and shows a loading spinner. This works in all other situations, except that outlined below.

The handleRedirect function looks as follows:

func handleRedirect(_ context: NSManagedObjectContext, url: URL) {
    
    debugPrint("Handling redirect")
    let url = URLComponents(string: url.absoluteString)!
    
    let code = url.queryItems?.first(where: { $0.name == "code" })?.value
    trueLayerClient.getAccessToken(code: code!) { res in
        
        if res == nil {
            debugPrint("accessTokenResponse was nil")
        }
        
        self.api.storeTokens(
            str: API.StoreTokensRequest(
                userID: "***",
                authToken: res!.accessToken,
                refreshToken: res!.refreshToken,
                apiKey: "***"
            ), finished: { success in
                if success{
                    debugPrint("was successful")
                    DispatchQueue.main.async{
                        self.isLoading = false
                    }
                } else {
                    debugPrint("store token failed")
                }
            })
    }
}

I'm triggering this onOpenUrl using a universal Link I have setup.

When I hit the link, my app opens from the background and I see the following logs:

Handling Redirect

Was successful

However, the app never goes into a loading state. Furthermore, the UI becomes "blocked" and I have to hard kill the app to be able to press anything.

Once I do reopen the app, the new state (which I fetch via api and store in CoreData) is reflected in the view.

At first I thought my API was responding too quickly, but I put a 5 second sleep in it and I still see the UI get blocked but with the same logs (just further apart).

I would appreciate any help on this.

If helpful, my storeTokens API call looks like this:

func storeTokens(str: StoreTokensRequest , finished: @escaping (Bool)->Void) {
    let u = URL(string:"\(self.baseURL)/\(storeTokenPath)")!
    
    var req = URLRequest(url: u)
    req.addValue("application/json", forHTTPHeaderField: "Content-Type")
    req.httpMethod = "POST"
    
    let reqBody = str
    
    debugPrint("req bodyed")
    
    guard let encoded =  try? JSONEncoder().encode(reqBody) else {
        debugPrint("failed to encode req")
        finished(false)
        return
    }
    req.httpBody = encoded
    
    debugPrint("encoded")
    
    
    let task =  URLSession.shared.dataTask(with: req) { data, response, error in
        
        guard let httpResponse = response as? HTTPURLResponse else {
            debugPrint("wasnt http rep")
            
            finished(false)
            return
        }
        
        debugPrint("status code is: \(httpResponse.statusCode)")
        
        if httpResponse.statusCode < 299 {
            debugPrint("About to call true")
            finished(true)
            return
        }
    }
    
    task.resume()
}
}

I see all the logs in this function in my output too, I just left them out for succinctness.

1 Answers

I have tried an implementation similar to yours. My "onOpenUrl()" method is waking up, if necessary, my app, and passing the url to my app, and the app is updating its state correctly.

Basic check.

Forget for a moment "onOpenUrl". Implement inside your view this method:

.onAppear {
    viewModel.onAppear()
}

where inside your view model play with the "isLoading" property. For example,

   func onAppear(){
      self.isLoading = true
      DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
         print("- loading complete")
         self.isLoading = false
      }
   }

Does the view update (the activity loader) accordingly?

Related