【发布时间】:2019-05-03 18:29:52
【问题描述】:
我正在尝试从 Firebase 实时数据库中检索一些加密消息,对其进行解密,然后将它们显示在 CollectionView 中。解密过程是成功的,但是我遇到了一个关于多线程的问题:添加到Messages数组中的获取解密消息的顺序是错误的,所以它们没有以正确的顺序显示在CollectionView中,显示消息的顺序CollectionView 在每次运行期间都会有所不同。我认为出现这个问题是因为每个加密消息完成解密过程所需的时间不同,有些加密消息需要更多时间来解密,有些加密消息比其他加密消息先完成解密,所以它们添加到 Messages 数组的顺序是不再正确。我期望的工作流程:
- 向 Firebase 数据库上的消息节点发出 fetch 请求
- 对于每条获取的消息:
3.1。解密它
3.2。将其附加到 Messages 数组
3.3。重新加载 CollectionView 以更新 UI
但我不知道如何使用 GCD 来正确实现这一点,因为并发问题,显示消息的顺序不正确。但是,我找到了一个解决方案,如果我尝试在我的代码中放置 sleep(1) 命令,代码可以正常运行,但是由于 sleep 命令,它太慢了。我尝试了很多方法,但似乎都不对,除了使用sleep(1) 命令。请帮助我正确执行此操作,非常感谢!这是我的代码:
func observeMessage(){
self.eThree = VirgilHelper.sharedVirgilHelper.eThreeToUse!
// Get current user's UID
guard let uid = FIRAuth.auth()?.currentUser?.uid , let toId = self.user?.id else {
return;
}
let userMessagesRef = FIRDatabase.database().reference().child("user-messages").child(uid).child(toId);
userMessagesRef.observe(.childAdded, with: { (snapshot) in
let messageId = snapshot.key;
let messagesRef = FIRDatabase.database().reference().child("messages").child(messageId);
// Observe the entire value of that node
messagesRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String:AnyObject] {
//sleep(1) // The working sleep command, but it's too slow
let message = Message(dictionary: dictionary)
if let fromUID = message.fromId, let toUID = message.toId, let cipherText = message.text {
self.eThree!.lookupPublicKeys(of: [fromUID], completion: { (lookupResult, error) in
if error != nil {
print("Error when looking up the Public Key of UID \(fromUID), \(String(describing: error))")
}
if let lookupResult = lookupResult {
message.text = try! self.eThree!.decrypt(text: cipherText, from: lookupResult[fromUID]!)
print("text: \(message.text)")
// The concurency prolem happens at here
self.messages.append(message);
// Go back to main thread to update UI
DispatchQueue.main.async {
// The concurency prolem happens at here, UI doesn't display with correct order of fetched-decrypted messages
self.collectionView?.reloadData()
let indexPath = IndexPath(item: self.messages.count-1, section: 0)
self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true);
}
}
})
}
}
}, withCancel: nil)
}, withCancel: nil)
}
【问题讨论】:
标签: swift firebase asynchronous grand-central-dispatch