Swift -Firebase is it possible to Post and Observe at same time

雨燕双飞 提交于 2020-05-17 09:33:07

问题


When I want to observe I run:

let likesRef = Database.database().reference().child("likes").child(postId)
likesRef.observeSingleEvent(of: .value, with:{ (snapshot) in

    let likes = snapshot.childrenCount

    let totalLikes = Int(likes)

    // display totalLikes
})

When I want to post I run:

let dict = [uid: 1]
let likesRef = Database.database().reference().child("likes").child(postId)
likesRef.updateChildValues(dict) { [weak self](error, ref) in
    if let error = error { return }
    // if no error then update the ref 
})

When posting the completionBlock has 2 values:

withCompletionBlock: (Error?, DatabaseReference)

Is there a way that I can also observe the ref that I am posting to using the 2nd completionBlock value: DatabaseReference:

For eg once the user likes something I want to update the ref and display the new number of likes at the same time without having to run observeSingleEvent:

let dict = [uid: 1]
let likesRef = Database.database().reference().child("likes").child(postId)
likesRef.updateChildValues(dict) { (error, ref) in

    if let error = error { return }

    // *** somehow get the total amount of likes from the ref *** 

    // If possible I want to avoid this code below
    likesRef.observeSingleEvent(of: .value, with:{ (snapshot) in

        let likes = snapshot.childrenCount

        let totalLikes = Int(likes)

        // display totalLikes
     })
})

回答1:


Here's some very abbreviated code to accomplish the task of adding a users uid who likes a post and incrementing a counter via runTransactionBlock. Keep in mind there are 100 ways to do this.

A proposed structure

all_posts
   post_0
      like_count: 2
      post: "Hello, World"

likes
   post_0
      uid_0: true
      uid_1: true

Based on the question and discussion, I broke the posts and likes into separate nodes. The reasoning is that when the posts are loaded, they will probably be displayed in a list and all that's really needed at that point is the post topic and the total number of likes, so I made 'like_count' part of the post node.

If we added the actual likes within the post node itself, it could be 10,000 or 10,000,000 and there's no reason to load all of that data when loading in the posts. Having that many likes could also overwhelm the device.

Within the likes node, each post key references the post in the all_posts node. The children are the uid's of the users that liked the post and the value is a boolean 'true' as a placeholder. Nodes with no values cannot exist so 'true' keeps it in place and is a tiny amount of data.

Then the code -

func updatePostWithLikesViaTransaction() {
    let postsRef = self.ref.child("all_posts") //self.ref points to my Firebase
    let thisPostRef = postsRef.child("post_0")

    thisPostRef.runTransactionBlock ({ (currentData: MutableData) -> TransactionResult in
        if var data = currentData.value as? [String: Any] {
            var count = data["like_count"] as? Int ?? 0
            count += 1
            data["like_count"] = count
            currentData.value = data
        }

      return TransactionResult.success(withValue: currentData)
    }) { (error, committed, snapshot) in
        if let error = error {
            print(error.localizedDescription)
            return
        }
        print("successfully incremented counter")
        let likesRef = self.ref.child("likes")
        let likesPostRef = likesRef.child(thisPostRef.key!)
        likesPostRef.child("uid_2").setValue(true)
    }
}

The above is not ideal by any means but demonstrates the process (and works with the presented structure).

First we get a reference to the post we want to update and then within a transaction block read the currentData 'like_count' child which would return 2 based on the values in the structure. That's incremented to 3, updated within currentData and then updated via the TransactionResult.

runTransactionBlock also has an optional completion callback and we are using that to, upon success, update the post within the likes with the users uid and true.

The end result of running this is that the counter is incremeted to 3 and 'uid_2: true' is added to the 'likes/post_0' node




回答2:


Actually its not possible to get both Event at same time. Once you like once your data reach at firebase database then you will get Value,Change,ChieldAdded event on App side. It will take 1-2 second or less depend on Internet. So Post will call first and then observer will call.

You can get observer this by two ways:

Step 1 : Add Child Change listener

let likesRef = Database.database().reference().child("likes").child(postId)
likesRef.observe(.childChanged, with: {
        (snapshot) in

    let likes = snapshot.childrenCount

    let totalLikes = Double(Int(likes))

    // display likes
 })

Child change listener listens changes on snapshot

Step 2 : Put value listener

let likesRef = Database.database().reference().child("likes").child(postId)
likesRef.observe(.value, with: {
        (snapshot) in

    let likes = snapshot.childrenCount

    let totalLikes = Double(Int(likes))

    // display likes
 })

Value listener listens every time

I Hope this will help...



来源:https://stackoverflow.com/questions/60653860/swift-firebase-is-it-possible-to-post-and-observe-at-same-time

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