Firebase one of two observers not working

无人久伴 提交于 2019-12-25 16:07:28

问题


I have two observers, the second observer is dependent on the first observers value. I can't seem to get the first observer to work, I am not getting any errors on Xcode. The first function has to check the Users profile for information and then use that information to search for different information in the database. Here is my code:

func loadposts() {
    ref = Database.database().reference()
    let trace = Performance.startTrace(name: "test trace")
    trace?.incrementCounter(named:"retry")
    let userID = Auth.auth().currentUser?.uid
    print(userID!)


   ref.child("Users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
        // Get user value
        let value = snapshot.value as? NSDictionary
        let one1 = value?["Coupon Book"] as? String ?? ""
        print("one1: \(one1)")
        self.bogus.set(one1, forKey: "bogus")
    }) { (error) in
        print(error.localizedDescription)
    }

    delay(0.1) {
    print("bogus: \(self.bogus.string(forKey: "bogus"))")
    Database.database().reference().child("Coupons").child(self.bogus.string(forKey: "bogus")!).observe(.childAdded) { (Snapshot : DataSnapshot) in
        if let dict = Snapshot.value as? [String: Any] {
            let captiontext = dict["company name"] as! String
            let offerx = dict["offer count"] as! String
            let logocomp = dict["logo"] as! String
            let actchild = dict["childx"] as! String
            let post = Post(captiontext: captiontext, PhotUrlString: actchild, offertext: offerx, actualphoto: logocomp)
            self.posts.append(post)
            self.tableview.reloadData()

            print(self.posts)
        }
    }
    }
    trace?.stop()
}

Any help is appreciated.


回答1:


self.bogus.string(forKey: "bogus"))" is nil because observeSingleEvent is an async method, so to get the required results you need to call the second observer inside the first observer or you can use the completion handler

You can use the completionHandler like this:

guard let uid = Auth.auth().currentUser?.uid else {
    return
  }

    func firstObserverMethod(completionCallback: @escaping () -> Void) {

                ref.child("Users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
                    // Get user value
                    if let value = snapshot.value as? [String: Any] {
                          let one1 = value["Coupon Book"] as? String

                          print("one1: \(one1)")
                          self.bogus.set(one1, forKey: "bogus")
                          completionCallback()

                    }




                }) { (error) in
                    print(error.localizedDescription)
                }
            }

Now using the above method:

    firstObserverMethod {

                     print("bogus: \(self.bogus.string(forKey: "bogus"))")
                     guard let bogusString = self.bogus.string(forKey: "bogus") else {                
                            print("bogus is not set properly")
                            return
                     } 


 Database.database().reference().child("Coupons").child(bogusString).observe(.childAdded) { (Snapshot : DataSnapshot) in
                        if let dict = Snapshot.value as? [String: Any] {
                            let captiontext = dict["company name"] ?? ""
                            let offerx = dict["offer count"] ?? ""
                            let logocomp = dict["logo"] ?? ""
                            let actchild = dict["childx"] ?? ""
                            let post = Post(captiontext: captiontext, PhotUrlString: actchild, offertext: offerx, actualphoto: logocomp)
                            self.posts.append(post)
                            DispatchQueue.main.async {
                                   self.tableview.reloadData()
                            }


                            print(self.posts)
                        }
                    }

                }

Note: You should use optional binding to get the values from optional




回答2:


Since you are using the result of the 1st observer in the reference of your 2nd observer, it's a very bad idea to add the 2nd observer right below the first observer. And adding a delay won't be a viable solution : these two calls are asynchronous, which means that the reason why you are not getting might very likely be because the 2nd observer is triggered even before the 1st has returned any data.

The solution here, would be using a completion handler, or you could just incorporate your 2nd observer inside the completion block of the 1st, to be make sure that the proper order (1st observer -> 2nd observer) will always be respected.

It would look somehow like this:

func loadposts() {

    // ...

    // 1st Observer here

    ref.child("Users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in

       // Get your value here

       guard let one1 = snapshot.childSnapshot(forPath: "Coupon Book").value as? String else { return }

       // 2nd Observer here. Now you can use one1 safely:

       Database.database().reference().child("Coupons").child(one1).observe(.childAdded) { (Snapshot : DataSnapshot) in

            // ...

        }

    })

}

Now, a couple of things that you could also improve in your code, while not directly related to the question:

I would suggest you to make use of guard statements instead force-unwrapping, which may end up in crashing your app at some point.

For example, you could check whether your current user exist or not like so:

guard let currentUserID = Auth.auth().currentUser?.uid else {
    return
}

// Now you can use safely currentUserID

Also, when you try to get the data out of the snapshot, it's not a good idea either, to use force-casting. You would better write it in this way:

   yourRef.observeSingleEvent(of: .value, with: { (snapshot) in

         for child in snapshot.children.allObjects as! [DataSnapshot] {

         guard let text = child.childSnapshot(forPath: "text").value as? String, let somethingElse =  child.childSnapshot(forPath: "otherValue").value as? NSNumber else {
             return
         }

         // And so on, depending of course on what you have in your database.

  }


来源:https://stackoverflow.com/questions/46356012/firebase-one-of-two-observers-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!