ios - 使用 DispatchSemaphore wait() 冻结应用程序
问题描述
我创建了一个函数 getFriends,它从 firestore 读取用户的好友列表并将每个好友放入 LocalUser 对象(这是我的自定义用户类)中,以便在表格视图中显示好友列表。我需要 DispatchSemaphore.wait() 因为我需要 for 循环仅在调用 for 循环内的完成处理程序时进行迭代。加载视图时,应用程序冻结。我知道问题是在主线程中调用了 semaphore.wait() 。但是,通过阅读 DispatchQueue-tutorials,我仍然不明白如何解决这个问题。另外:您是否看到任何更简单的方法来实现我想做的事情?
这是我对 viewDidLoad() 中函数的调用:
self.getFriends() { (friends) in
self.foundFriends = friends
self.friendsTable.reloadData()
}
和函数getFriends:
let semaphore = DispatchSemaphore(value: 0)
func getFriends(completion: @escaping ([LocalUser]) -> ()) {
var friendsUID = [String : Any]()
database.collection("friends").document(self.uid).getDocument { (docSnapshot, error) in
if error != nil {
print("Error:", error!)
return
}
friendsUID = (docSnapshot?.data())!
var friends = [LocalUser]()
let friendsIdents = Array(friendsUID.keys)
for (idx,userID) in friendsIdents.enumerated() {
self.getUser(withUID: userID, completion: { (usr) in
var tempUser: LocalUser
tempUser = usr
friends.append(tempUser)
self.semaphore.signal()
})
if idx == friendsIdents.endIndex-1 {
print("friends at for loop completion:", friends.count)
completion(friends)
}
self.semaphore.wait()
}
}
}
FriendsUID 是一个字典,每个朋友的 uid 作为键,true 作为值。因为我只需要密钥,所以我将它们存储在数组 friendsIdents 中。函数 getUser 在 firestore 中搜索传递的 uid 并创建相应的 LocalUser (usr)。这最终被附加到朋友数组中。
解决方案
你几乎不应该在主线程上有一个 semaphore.wait() 。除非您希望等待 < 10 毫秒。
相反,请考虑将您的朋友列表处理分派到后台线程。后台线程可以在不阻塞主线程的情况下执行对您的数据库/api 和 wait() 的分派。
如果您需要触发任何 UI 工作,请确保使用该线程中的 DispatchQueue.main.async {}。
let semaphore = DispatchSemaphore(value: 0)
func getFriends(completion: @escaping ([LocalUser]) -> ()) {
var friendsUID = [String : Any]()
database.collection("friends").document(self.uid).getDocument { (docSnapshot, error) in
if error != nil {
print("Error:", error!)
return
}
DispatchQueue.global(qos: .userInitiated).async {
friendsUID = (docSnapshot?.data())!
var friends = [LocalUser]()
let friendsIdents = Array(friendsUID.keys)
for (idx,userID) in friendsIdents.enumerated() {
self.getUser(withUID: userID, completion: { (usr) in
var tempUser: LocalUser
tempUser = usr
friends.append(tempUser)
self.semaphore.signal()
})
if idx == friendsIdents.endIndex-1 {
print("friends at for loop completion:", friends.count)
completion(friends)
}
self.semaphore.wait()
}
// Insert here a DispatchQueue.main.async {} if you need something to happen
// on the main queue after you are done processing all entries
}
}
推荐阅读
- swift - swift中的线程1信号sigabrt
- r - R 用于解决线性规划营销问题
- python - 使用 pip install leveldb 时出现错误
- react-native - Reactnavigation - 不要按返回按钮返回登录屏幕
- typescript - 将本地 JS 模块导入 TS 文件的最简单方法是什么?
- typescript - 如何修复打字稿中的“不能将命名空间用作类型 ts(2709)”?
- python - 使用 Tkinter 移动图像
- .net-core - Protobuf-net 缺少依赖 System.Private.ServiceModel
- php - 对 PHP REST API 的 POST 请求仅适用于 Postman
- google-sheets - 如果单元格 A > 单元格 B,则有条件地锁定 Google 表格中的单元格