0

The rule is that "if you update the user-interface inside a closure that works in another thread, then you should call in DispatchQueue.main.async method. However, after I retrieved the data from the Firestore, tableview.reloadData() still works without the existence of DispatchQueue.main.async method and it works in MainThread inside the closure. How would be it possible? Is something changed? Xcode version 12.4; Swift version 5

   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)
                    }
                }
            }
            if Thread.isMainThread{
                self.tableView.reloadData()
            }
        }
    }
}
Akif
  • 73
  • 5
  • Check what's the thread you're in when calling it. `Thread.isMainThread`, or using a breakpoint... The closure might be called in main... – Larme Sep 21 '21 at 12:49
  • The rule is that "if you update on user-interface inside a closure, then you should call in DispatchQueue.main.async method -- No. The rule is "You should deal with UI on the main thread only" – Andrey Chernukha Sep 21 '21 at 12:50
  • @Akif How do you know that? Do you see Xcode non main thread ui access logging in console? – Andrey Chernukha Sep 21 '21 at 12:54
  • @AndreyChernukha, you are right, I have checked it and then I understand that I am in mainThread. – Akif Sep 21 '21 at 12:59
  • @Larme Yes, it looks like I am in the main thread when I called reloaddata inside the closure. – Akif Sep 21 '21 at 13:03
  • 1
    Let's clarify: Inside a closure, then is no guarantee that you are in main thread or not. So depending on how it's coded (see the doc if needed), you could be inside main thread, the thread which call the method, a "random" background thread, etc. – Larme Sep 21 '21 at 13:06
  • Checked the doc here and there (https://cloud.google.com/firestore/docs/query-data/get-data#swift_1 & https://firebase.google.com/docs/reference/swift/firebasefirestore/api/reference/Classes/Query). No luck here. If there was an illegal access to UI outside of the main thread you would have gotten a square shaped purple warning in xcode, it tends to indicate you are on the main thread. On the other hand as @Larme said, there is no guarantee that it's the case, you should encapsulate this method in a synchronous block (even more true while using a third party framework) – Olympiloutre Sep 21 '21 at 13:18

1 Answers1

0

The Firestore SDK (and most Firebase SDKs) invoke your callback on the main thread, precisely so that you can easily update the UI. They transition to the main thread, so that you don't have to.

Also see my answer here:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807