I am writing some code to let the user tap a button to log in, and after the login is successful, immediately make another call to pull in data from the system if it's available. I'm a little confused about where I need/don't need to wrap my code in different thread blocks. Can I just put everything in DispatchQueue.main.async given that I'm doing UI work on the main thread? Here is my code flow - I was wondering if someone could review and let me know if I've got the right structure of wrapping code in async/main thread blocks.
let messageFrame = AlertCreator.progressBarDisplayer(view: self.view, message: "Loading", true)
DispatchQueue.main.async(execute: {
//Present loading spinner while call is made
self.view.addSubview(messageFrame)
//Make an AUTH call using URLSession.shared.dataTask (with callback)
UserSecurityService.AuthenticateUser(username: self.txtUsername.text!, password: self.txtPassword.text!)
{ (authenticationResponse) -> () in
if (authenticationResponse.Status == ResponseCode.LOGIN_SUCCESS)
{
//If this user logged in successfully, and now need to import data, then do so, otherwise just proceed to the app.
if (authenticationResponse.Value!.HasDataForImport) {
//Make ANOTHER async call using URLSession.shared.dataTask (with callback)
UserDataService.GetUserSettings()
{ response in
//Remove the spinner
messageFrame.removeFromSuperview()
if (response.Status == ResponseCode.OK)
{
//Success, go to dashboard
self.presentHomeViewController()
}
else {
//Show alert failure, with clicking 'ok' firing a callback to take the user to the dashboard
}
}
}
else {
//Data does not exist, so just stop the spinner and take the user to the dashboard
self.presentHomeViewController()
}
else if (authenticationResponse.Status == ResponseCode.INVALID_USERNAME_PASSWORD) {
//User entered the wrong username/password
messageFrame.removeFromSuperview()
<alert is created/presented here>
}
}) //main dispatch async execute
If you noticed, I am making an async call to authenticate, that does something on the UI (shows a spinner to prevent any other activity, checks if the login was successful or not, and removes the spinner. It also potentially presents an alert, and then takes the user to a view controller.
My questions specifically are:
- Should I not wrap this entire block in DispatchQueue.main.async, but rather only the two web calls? I've done all kinds of combinations, most of which worked (and some that crashed), so I'm not entirely sure if I just need DispatchQueue.main.async, or need something nested inside of it such as a DispatchQueue.global(qos: DispatchQoS.QoSClass.userInteractive).async as well?
- Should I wrap each web call, or only the outer one
- Should I be wrapping the UI-related things in their own blocks, for example when I present alerts, view controllers, or even stop the spinner? 3.
Thank you for any assistance / suggestions you could provide!