Swift -Firebase是否可以同时发布和观察 [英] Swift -Firebase is it possible to Post and Observe at same time

查看:63
本文介绍了Swift -Firebase是否可以同时发布和观察的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我想observe时,我运行:

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
})

当我要发布时,我运行:

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 
})

发布时completionBlock具有2个值:

withCompletionBlock: (Error?, DatabaseReference)

有没有办法我也可以使用第二个completionBlockDatabaseReference:

例如,一旦用户喜欢了某件东西,我想更新参考并同时显示新的喜欢数,而不必运行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
     })
})

解决方案

下面是一些非常简短的代码,以完成添加喜欢帖子的用户uid并通过runTransactionBlock递增计数器的任务.请记住,有100种方法可以做到这一点.

建议的结构

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

likes
   post_0
      uid_0: true
      uid_1: true

基于问题和讨论,我将帖子和喜欢的内容分解为单独的节点.原因是,当帖子被加载时,它们可能会显示在列表中,而此时真正需要的就是帖子主题和总点赞次数,因此我将"like_count"设置为帖子节点的一部分. /p>

如果我们在post节点本身中添加实际的点赞,则可能为10,000或10,000,000,并且在加载帖子时没有理由加载所有这些数据.拥有如此多的喜欢也可能使该设备不知所措.

在likes节点中,每个帖子关键字都引用all_posts节点中的帖子.子代是喜欢该帖子的用户的uid,其值是一个布尔"true"作为占位符.没有值的节点将不存在,因此"true"将其保留在原处,并且是少量数据.

然后输入代码-

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)
    }
}

以上内容无论如何都不是理想的,但它演示了该过程(并适用于所介绍的结构).

首先,我们获得要更新的帖子的引用,然后在事务块中读取currentData'like_count'子元素,该子元素将根据结构中的值返回2.增量为3,在currentData中更新,然后通过TransactionResult更新.

runTransactionBlock还有一个可选的完成回调,我们将其用于成功后使用用户uid和true在赞中更新帖子.

运行此命令的最终结果是将计数器增加为3,并将"uid_2:true"添加到"likes/post_0"节点

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
     })
})

解决方案

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

这篇关于Swift -Firebase是否可以同时发布和观察的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆