Как сделать общий ресурс потокобезопасным при использовании диспетчерской группы?
У меня есть класс User, который нужно обновлять каждый раз, когда пользователь открывает приложение.
class User : NSObject, NSCoding {
var vehicles : [Vehicles]
var bankaccounts : [BankAccounts]
var friends : [Friends]
}
На моем домашнем экране ViewController у меня есть функция, которая получает данные из бэкэнда, используя 3 запроса Alamofire. Наконец, я сохраняю данные в UserDefaults. DispatchGroup была первым, что пришло мне в голову, чтобы реализовать это. Вот код
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")
}
}
Но я не совсем уверен в безопасности потока моего пользовательского объекта. Поскольку он будет обновляться в трех разных обратных вызовах, будет ли здесь проблема с потокобезопасностью? Если да, то как лучше всего решить проблему? Я думал об использовании DispatchSemaphore. Но я не уверен, что это правильный подход.
1 ответ
Ты спрашивал:
Но мне непонятна безопасность потоков моего пользовательского объекта. Поскольку он будет обновляться в трех разных обратных вызовах, будет ли здесь проблема с потокобезопасностью?
В вашем фрагменте кода нет проблем с безопасностью потоков, потому что Alamofire вызывает свои обработчики завершения в основном потоке. Они делают это, чтобы уменьшить проблемы с многопоточностью. Нет необходимости вDispatchQueue.main.async
в этом случае. Как говорится в документации Alamofire:
Замыкания, передаваемые обработчикам ответов, выполняются на
.main
очередь по умолчанию, но определеннаяDispatchQueue
можно передать, чтобы выполнить закрытие.
Поэтому, если вы не сделали что-то необычное (например, переопределили значение по умолчанию .main
очередь с некоторыми параллельными DispatchQueue
), Alamofire будет запускать свои обработчики завершения в основном потоке, уменьшая проблемы безопасности потоков.
Если вы использовали другой API, который не вызывал обработчики завершения в основном потоке (например, URLSession.shared
вызывает обработчики завершения в фоновой очереди), тогда могут возникнуть проблемы, но не с Alamofire. (И дажеURLSession
использует последовательную фоновую очередь, поэтому не будет проблем с использованием вашего шаблона, когда вы обновляете локальную переменную.)
Итог: пока вы не изменяете / не получаете доступ к переменной из нескольких потоков одновременно, проблемы безопасности потоков в значительной степени смягчаются.