通过Firebase在Swift内建立向上投票/向下投票系统

通过Firebase在Swift内建立向上投票/向下投票系统,swift,firebase,firebase-realtime-database,firebase-authentication,Swift,Firebase,Firebase Realtime Database,Firebase Authentication,我已经查阅了数小时的代码和注释,我正在努力寻找任何有助于我在使用firebase的swift应用程序中对对象进行上下投票的文档 我有一个照片库,我希望在图片中添加instagram风格的upvote。该用户已使用firebase auth登录,因此我有他们的用户ID 我只是想弄清楚firebase中需要设置的方法和规则 任何帮助都是很棒的。我自己也不是一个敏捷的家伙(双关语!),但我想我有你大部分的答案 然后,您只需使用两个if语句,根据您是想投票赞成还是反对,从交易中返回正确的值。我将介绍如何

我已经查阅了数小时的代码和注释,我正在努力寻找任何有助于我在使用firebase的swift应用程序中对对象进行上下投票的文档

我有一个照片库,我希望在图片中添加instagram风格的upvote。该用户已使用firebase auth登录,因此我有他们的用户ID

我只是想弄清楚firebase中需要设置的方法和规则

任何帮助都是很棒的。

我自己也不是一个敏捷的家伙(双关语!),但我想我有你大部分的答案


然后,您只需使用两个if语句,根据您是想投票赞成还是反对,从交易中返回正确的值。

我将介绍如何使用
Swift
Firebase
在社交网络应用程序中实现此功能

由于向上投票和向下投票是类似的,所以我将仅描述向上投票

总体思路是将计数器直接存储在与计数器相关的图像数据对应的节点中,并使用事务写入更新计数器值,以避免数据中的不一致。

例如,假设您将单个图像数据存储在路径
/images/$imageId/
处,其中
$imageId
是用于标识特定图像的唯一id,例如可以由Firebase For iOS中包含的函数生成。然后,与该节点上的单个照片对应的对象如下所示:

$imageId: {
   'url': 'http://static.example.com/images/$imageId.jpg',
   'caption': 'Some caption',
   'author_username': 'foobarbaz'
}
我们要做的是向该节点添加一个upvote计数器,使其成为:

$imageId: {
   'url': 'http://static.example.com/images/$imageId.jpg',
   'caption': 'Some caption',
   'author_username': 'foobarbaz',
   'upvotes': 12,
}
创建新图像时(可能是用户上载图像时),可能需要使用
0
或其他一些常量初始化upvote计数器值,具体取决于您想要实现的目标

在更新特定计数器时,您希望使用事务以避免其值不一致(当多个客户端同时更新计数器时,可能会发生这种情况)

幸运的是,在
Firebase
Swift
中处理事务写入非常简单:

func upvote(imageId: String,
            success successBlock: (Int) -> Void,
            error errorBlock: () -> Void) {

    let ref = Firebase(url: "https://YOUR-FIREBASE-URL.firebaseio.com/images")
        .childByAppendingPath(imageId)
        .childByAppendingPath("upvotes")

    ref.runTransactionBlock({
        (currentData: FMutableData!) in

        //value of the counter before an update
        var value = currentData.value as? Int

        //checking for nil data is very important when using
        //transactional writes
        if value == nil {
            value = 0
        }

        //actual update
        currentData.value = value! + 1
        return FTransactionResult.successWithValue(currentData)
        }, andCompletionBlock: {
            error, commited, snap in

            //if the transaction was commited, i.e. the data
            //under snap variable has the value of the counter after
            //updates are done
            if commited {
                let upvotes = snap.value as! Int
                //call success callback function if you want
                successBlock(upvotes)
            } else {
                //call error callback function if you want
                errorBlock()
            }
    })
}
上面截取的代码实际上几乎正是我们在生产中使用的代码。我希望它能帮助你:)

我很惊讶,但从原始文档中可以看出,它的工作方式很有魅力。它有一个缺点:如果有很多人喜欢json,json就会变得很大

FirebaseService.shared.databaseReference
            .child("items")
            .child(itemID!)
            .runTransactionBlock({ (currentData: MutableData) -> TransactionResult in
                if var item =  currentData.value as? [String : AnyObject] {
                let uid = SharedUser.current!.id

                var usersLikedIdsArray = item["liked_who"] as? [String : Bool] ?? [:]
                var likesCount = item["likes"] as? Int ?? 0

                    if usersLikedIdsArray[uid] == nil  {
                        likesCount += 1
                        usersLikedIdsArray[uid] = true
                        self.setImage(self.activeImage!, for: .normal)
                        self.updateClosure?(true)
                    } else {
                        likesCount -= 1
                        usersLikedIdsArray.removeValue(forKey: uid)
                        self.setImage(self.unactiveImage!, for: .normal)
                        self.updateClosure?(false)
                    }

                item["liked_who"] = usersLikedIdsArray as AnyObject?
                item["likes"] = likesCount as AnyObject?

                currentData.value = item

                return TransactionResult.success(withValue: currentData)
            }
            return TransactionResult.success(withValue: currentData)
        }) { (error, committed, snapshot) in
            if let error = error {
                self.owner?.show(error: error)
            }
        }

非常感谢。更详细地说:现在有了Firebase SDK更新,FMutableData变为FIRMutableData,FTransactionResult变为FirtTransactionResults,对于用户已经喜欢的情况,没有解决方案。而且它不仅仅是从+变为-。您应该存储用户ID并与当前用户ID进行比较,这要复杂得多。此方法可行,但也意味着同一用户可以多次向上投票。没有任何东西可以阻止它,因为正如@NikKov所说,需要有一种方法来比较已经投票的用户和即将投票的当前用户的uid。