Swift中的Upvote / Downvote系统通过Firebase

时间:2016-05-05 22:48:31

标签: swift firebase firebase-realtime-database firebase-authentication

我查看了几个小时的代码和备注,并且我正在努力寻找任何可以帮助我在使用firebase的swift应用程序中对一个对象进行upvoting和downvoting的文档。

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

我只是在努力想出这个方法以及需要在firebase中设置哪些规则。

任何帮助都会很棒。

3 个答案:

答案 0 :(得分:12)

我将介绍如何使用SwiftFirebase在社交网络应用Impether中实现此类功能。

由于上升和下调是类似的,我将仅描述上升。

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

例如,假设您在路径/images/$imageId/存储单个图像数据,其中$imageId是用于标识特定图像的唯一ID - 例如,可以通过函数{生成{ {3}}包含在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计数器值,具体取决于您想要实现的目标。

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

幸运的是,处理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()
            }
    })
}

上面的剪辑实际上几乎就是我们在制作中使用的代码。我希望它可以帮助你:)

答案 1 :(得分:1)

自己不是一个斯威夫特家伙(双关语!)但我认为this stackoverflow question有你的大部分答案。

然后,您只需使用几个if语句,根据您是要投票还是投票来从交易中返回正确的值。

答案 2 :(得分:1)

我非常惊讶,但原始文档中的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)
            }
        }