Upvote/Downvote 个系统 Swift 通过 Firebase

Upvote/Downvote system within Swift via Firebase

我已经查看了数小时的代码和注释,但我正在努力寻找任何可以帮助我在带有 firebase 的 swift 应用程序中对对象进行投票的文档。

我有一个照片库,我想为图片添加 Instagram 风格的点赞。用户已经使用 firebase auth 登录,所以我有他们的用户 ID。

我只是在努力想出方法以及需要在 firebase 中设置什么规则。

任何帮助都会很棒。

我自己不是 Swift 人(双关语!),但我认为 this Whosebug question 有你的大部分答案。

然后您只需使用几个 if 语句 return 根据您是要赞成票还是反对票从交易中获得正确的价值。

我将描述我如何使用 SwiftFirebase 在社交网络应用程序 Impether 中实现这样的功能。

由于赞成票和反对票是类似的,我将只描述赞成票。

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

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

$imageId: {
   'url': 'http://static.example.com/images/$imageId.jpg',
   'caption': 'Some caption',
   'author_username': 'foobarbaz'
}

我们要做的是给这个节点加一个upvote counter,所以变成:

$imageId: {
   'url': 'http://static.example.com/images/$imageId.jpg',
   'caption': 'Some caption',
   'author_username': 'foobarbaz',
   'upvotes': 12,
}

当您创建新图像时(可能是在用户上传图像时),您可能希望使用 0 或其他一些常量来初始化点赞计数器值,具体取决于您想要实现的目标。

当谈到更新一个特定的点赞数计数器时,您想使用事务来避免其值不一致(当多个客户端想要同时更新一个计数器时可能会发生这种情况)。

幸运的是,处理 FirebaseSwift 中的事务性写入非常容易:

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

上面的片段实际上几乎就是我们在生产中使用的代码。希望对你有帮助:)

我很惊讶,但是来自原始文档的 this code 很有魅力。它有一个缺点:如果点赞很多,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)
            }
        }