Search code examples
swiftcore-datagoogle-cloud-firestoreswift5nsmanagedobject

Saving empty data model after pulling data from Cloud Firestore with Core Data


The problem I am having is that Core Data is not saving correctly after communicating to Firestore database. I want to have every post's user image and name store in a cache for performance. Currently, I have two data model named Users and PostItem. Users is the one handling the user data that I want to save. I successfully was able to implement PostItem, but not Users.

I think it has something to deal with Firestore, but not entirely sure. The code:

     private var userName = String()
        private var imageLink = String()
        private var db = Firestore.firestore().collection("users")
        
        func fetchUser(_ id: String) -> String {
            db.document(id).getDocument { (snap, err) in
                if let snap = snap, snap.exists {
                    self.userName = snap.data()!["userName"] as! String
                } else {
                    print("Document does not exist")
                }
            }
            print("DB: \(self.userName)")
            return self.userName
        }
        
        func fetchUserImage(_ id: String) -> String {
            db.document(id).getDocument { (snap, err) in
                if let snap = snap, snap.exists {
                    self.imageLink = snap.data()!["image"] as? String ?? ""
                }else{
                    print("Document does not exist")
                }
            }
            print("DB: \(self.imageLink)")
            return self.imageLink
        }
        
        func setUpPosts(managedObjectContext: NSManagedObjectContext) {
            if !self.newposts.isEmpty{
                for i in self.newposts{
                    let user = Users(context: managedObjectContext)
                    print("Fetched Name: \(self.fetchUser(i.user))")
                    user.name = self.userName
                    print("Fetched Image: \(self.fetchUserImage(i.user))")
                    user.image = self.fetchUserImage(i.user)
                    user.uuid = i.user
                    
                    let post = PostItem(context: managedObjectContext)
                    post.type = i.type
                    post.user = i.user
                    post.image = i.thumb
                    post.id = i.id
                    post.text = i.text
                    post.comment = i.comments
                    post.video = i.media
                    do{
                        try managedObjectContext.save()
                    }catch{
                        print(error)
                    }
                    self.clearNewPosts()
                }
            }
        }

setUpPosts() is called from within the initializer of the class handling all post data for the views.


Solution

  • Most Firebase calls are asynchronous. In your code, db.document(id).getDocument is an asynchronous call, hence self.userName and self.imageLink will be empty/nil when you return from fetchUser/fetchUserImage.

    Firestore uses a local cache anyway (from the docs: "For Android and iOS, offline persistence is enabled by default."), so I wouldn't recommend implementing your own cache.

    For caching images, I'd recommend taking a look at FirebaseUI for iOS - is provides an integration with SDWebImage, which will handle caching for you.