Synchronized Array (for likes/followers) Best Prac

2020-02-26 12:36发布

问题:

I'm trying to create a basic following algorithm using Swift and Firebase. My current implementation is the following:

static func follow(user: FIRUser, userToFollow: FIRUser) {
    database.child("users").child(user.uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
        var dbFollowing: NSMutableArray! = snapshot.value!["Following"] as! NSMutableArray!
        dbFollowing?.addObject(userToFollow.uid)
        self.database.child("users/"+(user.uid)+"/").updateChildValues(["Following":dbFollowing!])
        //add user uid to userToFollows followers array in similar way
    }) { (error) in
        print("follow - data could not be retrieved - EXCEPTION: " + error.localizedDescription)
    }
}

This retrieves the array of from Firebase node Following, adds the uid of userToFollow, and posts the new array to node Following. This has a few problems:

  1. It is not synchronized so if it is called at the same time on two devices one array will overwrite the other and followers will not be saved.
  2. If there are no followers it cannot deal with a nil array, the program will crash (not the main concern, I can probably address with optionals).

I was wondering what the best practice might be to created a synchronized array of uid/tokens for user followers or post likes. I found the following links, but none seem to directly address my problem and seem to carry other problems with it. I figured it would be wise to ask the community with experience instead of Frankensteining a bunch of solutions together.

https://firebase.googleblog.com/2014/05/handling-synchronized-arrays-with-real.html https://firebase.google.com/docs/database/ios/save-data (the save data as transaction section)

Thanks for your help!

回答1:

Thanks to Frank, I figured out a solution using runTransactionBlock. Here it is:

static func follow(user: FIRUser, userToFollow: FIRUser) {
    self.database.child("users/"+(user.uid)+"/Following").runTransactionBlock({ (currentData: FIRMutableData!) -> FIRTransactionResult in
        var value = currentData?.value as? Array<String>
        if (value == nil) {
            value = [userToFollow.uid]
        } else {
            if !(value!.contains(userToFollow.uid)) {
                value!.append(userToFollow.uid)
            }
        }
        currentData.value = value!
        return FIRTransactionResult.successWithValue(currentData)
        }) { (error, committed, snapshot) in
            if let error = error {
            print("follow - update following transaction - EXCEPTION: " + error.localizedDescription)
        }
    }
}

This adds the uid of userToFollow to the array Following of user. It can handle nil values and will initialize accordingly, as well as will disregard the request if the user is already following the uid of userToFollow. Let me know if you have any questions!

Some useful links:

  1. The comments of firebase runTransactionBlock
  2. The answer to Upvote/Downvote system within Swift via Firebase
  3. The second link I posted above