1

So if I change it to .observe(DataEventType.value?, the problem does not occur.

What is the problem: If I open the app for the 2nd time or later after installing, it fails to fetch updated firebase data when using .observeSingleEvent. For example a new user added or a user who changed his profile picture. This problem does not occur when I change it to .observe(DataEventType.value?. It also gets resolved if I delete the app and run it again with .observeSingleEvent. That leads me to believe it is a cache issue that cause the 2nd run after install to behave differently to the first install.

I use keychain (not user defaults) for user info. Below is the code, and in bold the line where changing to .observe(DataEventType takes away the problem. Part 1 is where reload is done. Part 2 is a snapshot that the important part 3 is in, but can otherwise be disregarded. Part 3 is where the problem is.

////Part 1

func printPersonInfo(uid: String) {
    DispatchQueue.main.async{
        print(uid)
        self.table.reloadData()
    }
}


///Part 2

override func viewDidLoad() {
    super.viewDidLoad()
    
    
guard let myUid = Auth.auth().currentUser?.uid else { return }

refArtists = Database.database().reference().child("people").child(myUid).child("e2")

refArtists.observeSingleEvent(of:.value,  with: {snapshot in
    
    let myDomain = snapshot.value as? String
    self.bSnap = myDomain
    let peopleRef = Database.database().reference().child("people")
    let thisPersonRef = peopleRef.child(myUid).child("e2")
    thisPersonRef.observeSingleEvent(of:.value,  with: {snapshot in
        
        if snapshot.exists() {
   
            ........
                
                print(self.array1, "ahah")

            })
            
            
            ///Part 3
            
            
            let thisUsersUid = Auth.auth().currentUser?.uid //Mr. Sam's uid
            self.refArtists = Database.database().reference().child("people");
            **self.refArtists.observeSingleEvent(of: .value,  with: { [weak self]snapshot in**
                print("test test testa")
                guard let self = self else { return }
                if snapshot.childrenCount>0{
                    print("test test testb")
                    self.people.removeAll()
                    for people in snapshot.children.allObjects as! [DataSnapshot] {
                        if people.key != thisUsersUid {
                            print("peoplekey",people.key)

                            let peopleObject = people.value as? [String: AnyObject]
                            let peoplePhotoPosts = peopleObject?["PhotoPosts"]  as? String
                            let peopleimageDownloadURL = peopleObject?["imageDownloadURL"]  as? String
                            let peoplepostID = peopleObject?["postID"] as? String
                            let peopleCoordinates = peopleObject?["Coordinates"] as? String
                            let peoplecaption = peopleObject?["caption"] as? Int

                            let userId = people.key
                            
                            let coordSnap = people.childSnapshot(forPath: "Coordinates")
                            guard let lat = coordSnap.childSnapshot(forPath: "latitude").value as? CLLocationDegrees else { return /* put here something if your method does return some value */ }
                            guard let lon = coordSnap.childSnapshot(forPath: "longitude").value as? CLLocationDegrees else { return /* put here something if your method does return some value */ }
                            let locCoord = CLLocation(latitude: lat, longitude: lon)
                            print(userId, "coords: \(lat)  \(lon)")
                            print(peoplePhotoPosts as Any, "plpl")
                            print(peopleimageDownloadURL as Any, "dwl")

                            print("v", self.dict)
                            let coordSnap12 = people.childSnapshot(forPath: "caption").value as? Int ?? 0
                            let date = Date(timeIntervalSince1970: TimeInterval(coordSnap12)/1000.0)
                            //let secondsInDay = 86400
                            if Calendar.current.isDateInToday(date) {
                                
                                let distance = locCoord.distance(from: self.dict)
                                print(distance, "distancexy")
                                if distance/1609.344 < 3000 && self.array1.contains(people.key){
                                    print(self.array1, "f111111")
                                    print("fee", self.dict )
                                    print(distance, "distancexr")
                                    let peopl = Userx( PhotoPosts: peoplePhotoPosts, imageDownloadURL: peopleimageDownloadURL,........)
                                    self.people.append(peopl)
                                    let d = people.key as! String
                                    self.printPersonInfo(uid:d)
                                    
                                    
                                } else {
                                    print ("w")
                                }
                            } else {
                                print ("alphaaa")
                                
                            }
                }
                  print("aaaaaaaa", self.people.map {$0.distance})
                        
                    }
                    self.people.sort { ($0.distance ?? 0) < ($1.distance ?? 0) }
              }
           })
       }
    }
uuuuuu
  • 119
  • 1
  • 7
  • "it fails to fetch updated firebase data when using .observeSingleEvent" It's actually slightly different: it **does** fetch your data, but the callback is fired before that completes. So your callback gets the old data, and *then* the cache is update. This is definitely non-intuitive behavior and is why you should not combine disk persistence with `observeSingleEvent. Also see my longer explanation here: https://stackoverflow.com/questions/34486417/firebase-offline-capabilities-and-addlistenerforsinglevalueevent/34487195#34487195 – Frank van Puffelen Oct 23 '20 at 15:19
  • Thanks Frank. That is weird, but good to know. Would you recommend `addValueEventListener()` or `keepSynced(true)`? Would they even work with iOS, since the documentation is for android? I wanted to prevent unnecessary firebase hits, which is partially why I didn't want to use '.observe(DataEventType'. If I set persistence to false in my line `Database.database().isPersistenceEnabled = true` , I am a bit concerned that it will be inefficient. – uuuuuu Oct 23 '20 at 18:21
  • I typically **far** prefer having regular observers, instead of single-value observers. I only use `keepSynced(true)` on nodes that I really need to always have up to date in the cache. While it is a valid workaround, it is precisely that: a workaround. In most cases using a persistent listener is the proper solution. – Frank van Puffelen Oct 23 '20 at 18:58
  • Hmm. In that case, can I use .observe(DataEventType and somehow have it stop after a few seconds? That way it will properly load, but won't keep hitting firebase when the user scrolls or moves the phone. – uuuuuu Oct 24 '20 at 09:36
  • One issue is that you're reading the exact same node twice and there's no reason to do that. `refArtists = people/uid/e2` and then once you have that snapshot (inside the closure) the `peopleRef = people/uid/e2` again. You do not need keepSync'd and this `addValueEventListener` is android. You've asked similar questions previously as well and the issue is the same; it's not a Firebase issue - is the sequence in which you're calling your code/handling the data as @FrankvanPuffelen mentions above. What does this mean? *I use keychain (not user defaults) for user info* – Jay Oct 24 '20 at 13:16
  • Also, code like this `guard let self = self else { return }` will just silently fail and you'll never know why. This is kinda accurate *That leads me to believe it is a cache issue that cause the 2nd run after install to behave differently to the first install.* but it's not an issue, that's by design. Once a user is logged into Firebase they will stay logged in between application launches unless you specifically log them out. See [this answer](https://stackoverflow.com/questions/63802644/auto-login-with-firebaseui-on-ios/63802730#63802730) – Jay Oct 24 '20 at 13:24
  • I'm not sure what "won't keep hitting firebase when the user scrolls or moves the phone" means, but yes you *can* [remove listeners](https://firebase.google.com/docs/database/ios/read-and-write#detach_listeners) after some time. – Frank van Puffelen Oct 24 '20 at 15:04
  • @FrankvanPuffelen does keepSynced use too many resources in your opinion? I tried doing this with removed listeners while using `.observe(DataEventType.value`, but removing the listeners effective made it function like the SingleEvent, where callback fires before data is fetched (and since listener is removed, it doesn't fetch again). Right now keepSynced works, but I'm concerned it is unhealthy to use. Since by definition it is a permanent listener, that worries me on resource usage. – uuuuuu Oct 26 '20 at 23:29

0 Answers0