I have a class User which needs to be updated every time a user opens the app
class User : NSObject, NSCoding {
var vehicles : [Vehicles]
var bankaccounts : [BankAccounts]
var friends : [Friends]
}
In my home screen ViewController, I have a function that gets the data from backend using 3 Alamofire requests. Finally, I save the data in UserDefaults. DispatchGroup was the first thing that came to my mind to implement this. Here is the code
func loadUserData {
var user = User()
let userDataDispatchGroup = DispatchGroup()
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.vehicles array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.bankaccounts array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.friends array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.notify(queue: .main) {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: user)
UserDefaults.standard.set(encodedData, forKey: "user")
}
}
But I am not clear about the thread-safety of my user object. Since it will be updated in three different callbacks, would thread safety be an issue here? If yes, what would be the best way to solve the issue? I was thinking of using DispatchSemaphore. But I am not sure if that's the correct approach.
You asked:
But I am not clear about the thread-safety of my user object. Since it will be updated in three different callbacks, would thread safety be an issue here?
There are no thread-safety issues in your code snippet because Alamofire calls its completion handlers on the main thread. They do that to help mitigate multithreading concerns. There is no need for any DispatchQueue.main.async
in this case. As the Alamofire documentation says:
Closures passed to response handlers are executed on the
.main
queue by default, but a specificDispatchQueue
can be passed on which to execute the closure.
So unless you did something unusual (such as overriding the default .main
queue with some concurrent DispatchQueue
), Alamofire will run its completion handlers on the main thread, mitigating the thread-safety concerns.
If you were using a different API that didn’t call its completion handlers on the main thread (e.g. URLSession.shared
calls its completion handlers on a background queue), then there might be concerns, but not with Alamofire. (And even URLSession
uses a serial background queue, so there wouldn’t be issues using your pattern, where you are updating a local variable.)
Bottom line, as long as you’re not mutating/accessing a variable from multiple threads at the same time, threads-safety concerns are largely mitigated.