Firestore回调无需切换主队列即可调用tableView.reloadData()原因问询
现象原因
Firestore iOS SDK 默认将所有异步操作的回调(包括数据查询、写入、实时监听的回调)分发到**主队列(主线程)**执行,你测试时检测到回调处于主线程是符合SDK原生设计的行为,并非近期API调整导致的变化。
SDK做这个默认设计的核心考量是:
- 移动端绝大多数场景下,开发者拿到服务端返回数据后的第一操作就是更新UI,默认回调到主线程可以减少重复的线程切换样板代码,也能降低开发者忘记切主线程导致的UI异常、崩溃概率
- 如果你需要自定义回调线程,也可以通过
FirestoreSettings的callbackQueue参数自行指定队列,修改后回调就不会默认走主线程,此时就必须手动切主线程再更新UI
开发建议
就算当前默认回调在主线程,依然建议你显式使用
DispatchQueue.main.async包裹UI更新代码,原因如下:
- 避免后续项目调整Firestore全局回调队列配置后,回调不再走主线程,引发UI异常问题
- 代码可读性更强,维护者不需要回忆Firestore的特殊回调规则,一眼就能识别出这是UI更新操作,符合通用开发规范
你可以把代码调整为以下更安全的写法,就算当前已经在主线程,DispatchQueue.main.async也不会带来明显的额外性能损耗:
func loadMessages(){ messages = [] db.collection(K.FStore.collectionName).getDocuments { (querySnapShot, error) in if let err = error { print("There was an issue retrieving data from Firestore. \(err)") }else{ if let snapShotDocuments = querySnapShot?.documents{ for doc in snapShotDocuments{ let data = doc.data() if let messageSender = data[K.FStore.senderField] as? String,let messagebody = data[K.FStore.bodyField] as? String{ let newMessage = Message(sender: messageSender, body: messagebody) self.messages.append(newMessage) } } } DispatchQueue.main.async { self.tableView.reloadData() } } } }
内容的提问来源于stack exchange,提问作者Akif Acar
相关产品推荐
相关产品推荐

