【问题标题】:Loading all Users who liked a Post加载所有喜欢帖子的用户
【发布时间】:2017-10-07 02:16:30
【问题描述】:

我正在重建 Instagram,并希望显示所有喜欢帖子的用户。 我遇到了一个问题,我的 tableview 没有显示喜欢该帖子的用户。

为了喜欢,我会将它添加到 firebase

                    self.REF_LIKES_POSTS.child(postId).child(uid).setValue(true)

现在我想在我的 UsersLikedViewController 中获取所有喜欢该帖子的用户

  func loadUserLikes() {

    API.User.REF_POST_USERS_LIKED.observe(.childAdded, with: {
        snapshot in

        API.User.observeUserLikes(withPostId: snapshot.key, completion: {
            user in
            self.fetchUser(uid: user.id!, completed: {
                self.users.insert(user, at: 0)

                self.tableView.reloadData()
            })
        })
    })

}


func fetchUser(uid: String, completed: @escaping () -> Void) {

    API.User.observeUser(withId: uid, completion: {
        user in
        self.users.insert(user, at: 0)
        completed()
    })

}

我的用户 API

class UserApi {

var REF_USERS = FIRDatabase.database().reference().child("users")
var REF_POST_USERS_LIKED = FIRDatabase.database().reference().child("LikesFromUsers")
var REF_POST = FIRDatabase.database().reference().child("posts")


func observeUser(withId uid: String,  completion: @escaping (User) -> Void) {

    REF_USERS.child(uid).observeSingleEvent(of: .value, with: {
        snapshot in
        if let dict = snapshot.value as? [String: Any] {
            let user = User.transformUserInfo(dict: dict, key: snapshot.key)
            completion(user)
        }
    })
}



func observeUsers(completion: @escaping (User) -> Void) {
    REF_USERS.observe(.childAdded, with: {
        snapshot in
        if let dict = snapshot.value as? [String: Any] {
            let user = User.transformUserInfo(dict: dict, key: snapshot.key)
            if user.id! != API.User.CURRENT_USER?.uid {
                completion(user)

            }
        }

    })
}


func observeUserLikes(withPostId id: String , completion: @escaping (User) -> Void) {
    REF_POST_USERS_LIKED.child(id).observeSingleEvent(of: .value, with: {
        snapshot in
        if let dict = snapshot.value as? [String: Any]{
            let allUsers = User.transformUserInfo(dict: dict, key: snapshot.key)
            completion(allUsers)
        }
    })
}

}

我在 LoadUserLikes 中的 fetchUser() 函数返回 nil,因此缺少一些东西。 我只是实现了所有已经共享的帖子,因此用户可以关注和取消关注帖子,但这没有任何意义哈哈。

感谢您的宝贵时间

 "LikesFromUsers" : {
"-KjY30xwWA2IJBwlvyzf" : {
  "jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
}
  },
  "comments" : {
"-KjTIBDeMsho70t-jnGw" : {
  "commentText" : "klasse Auto",
  "creationDate" : 1.494083221667957E9,
  "likeCount" : 0,
  "uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
},
"-Kjc-uvCSn7qz8VkDVCR" : {
  "commentText" : "toll",
  "creationDate" : 1.494246203366448E9,
  "likeCount" : 0,
  "uid" : "es5fIbnKFpX4szcCbroUqHjJg6E3"
},
"-Kjc01pbWUtZn8XMlRGL" : {
  "commentText" : "fantatsico ",
  "creationDate" : 1.494246235776034E9,
  "likeCount" : 1,
  "likes" : {
    "es5fIbnKFpX4szcCbroUqHjJg6E3" : true
  },
   }
  },

"posts" : {
"-KjTBFFE5QzktG1IT5u0" : {
  "bookmarkCount" : 0,
  "caption" : "Toll",
  "commentCount" : 1,
  "creationDate" : 1.494081403379004E9,
  "hoursSinceUpload" : 0,
  "likeCount" : 0,
  "photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F76192CBE-55F0-4907-889A-849E196D5796?alt=media&token=de675609-4b73-411d-b402-f1ff3db64f79",
  "ratio" : 1.502732240437158,
  "score" : 16.38698994684219,
  "uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
},
"-KjTHFNe1RRS8Ly6bKsA" : {
  "bookmarkCount" : 1,
  "bookmarks" : {
    "jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
  },
  "caption" : "Traumhaft",
  "commentCount" : 0,
  "creationDate" : 1.494082976550228E9,
  "hoursSinceUpload" : 0,
  "likeCount" : 2,
  "likes" : {
    "es5fIbnKFpX4szcCbroUqHjJg6E3" : true,
    "jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
  },
  "photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F306BF7E1-9FEF-493A-ABF8-C0E061E8648F?alt=media&token=128bdd90-023a-49ac-8361-19c02c631183",
  "ratio" : 1.502732240437158,
  "score" : 166.6491847103437,
  "uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
},
"-KjY30xwWA2IJBwlvyzf" : {
  "bookmarkCount" : 1,
  "bookmarks" : {
    "jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
  },
  "caption" : "Traumwagen",
  "commentCount" : 2,
  "creationDate" : 1.494163133228368E9,
  "hoursSinceUpload" : 0,
  "likeCount" : 2,
  "likes" : {
    "es5fIbnKFpX4szcCbroUqHjJg6E3" : true,
    "jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
  },
  "photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F5C83FB24-BE21-49D9-863F-039FDE34969E?alt=media&token=e7e053a0-1966-4614-afad-42cab87f7880",
  "ratio" : 1.775,
  "score" : 280.0086305441856,
  "uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2",
  "videoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F5951720B-54F4-44C1-859C-43D8ACB98334?alt=media&token=02be7eaf-4970-4059-b07d-036a4f182b28"
    }
  },


 "users" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : {
  "email" : "user3@mail.de",
  "profilText" : "Schreib etwas über dich",
  "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/profile_image%2Fes5fIbnKFpX4szcCbroUqHjJg6E3?alt=media&token=ce8d8722-39bc-457a-8149-e51c837ef0a3",
  "username" : "Blondine",
  "username_lowercase" : "blondine"
},
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : {
  "email" : "user2@mail.de",
  "profilText" : "Schreib etwas über dich",
  "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/profile_image%2FjlkRoaucY6Q4GBkzhor5yAAl97I2?alt=media&token=197ee89d-c328-4d04-a56e-02a9450b1720",
  "username" : "Marie",
  "username_lowercase" : "marie"
},
"tH3714ywXTOgGK0cxBgGvTiSDLl2" : {
  "email" : "user1@mail.de",
  "profilText" : "Schreib etwas über dich",
  "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/profile_image%2FtH3714ywXTOgGK0cxBgGvTiSDLl2?alt=media&token=b08060a8-ef6b-4cf7-a73f-5bacd1ddada5",
  "username" : "Elena",
  "username_lowercase" : "elena"
}
  }
}

编辑:更多代码

 class HomeViewController: UIViewController {

@IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
@IBOutlet weak var tableView: UITableView!
var posts = [Post]()
var users = [User]()

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.estimatedRowHeight = 521
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.dataSource = self
    loadPost()



    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
    tableView?.refreshControl = refreshControl




}

func handleRefresh() {
   posts.removeAll()

    loadPost()
  tableView.reloadData()
   self.tableView?.refreshControl?.endRefreshing()

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "CommentSegue" {
        let commentVC = segue.destination as! CommentViewController
        let postId = sender as! String
        commentVC.postId = postId
    }

    if segue.identifier == "Home_ProfileSegue" {
        let profileVC = segue.destination as! ProfileUserViewController
        let userId = sender as! String
        profileVC.userId = userId
    }

    if segue.identifier == "Home_Hashtag" {
        let hashTagVc = segue.destination as! HashTagViewController
        let tag = sender as! String
        hashTagVc.tag = tag
    }
}



func loadPost() {

    API.Feed.observeFeed(withId: API.User.CURRENT_USER!.uid) { (post) in
        guard let postUid = post.userId else {
            return
        }
        self.fetchUser(uid: postUid, completed: {


            self.posts.insert(post, at: 0)
            self.tableView.reloadData()
        })
        API.Post.calculateScore(postId: post.id!, onSuccess: { (post) in


        }) { (errorMessage) in
            ProgressHUD.showError(errorMessage)
        }

    }



    API.Feed.observeFeedRemoved(withId: API.User.CURRENT_USER!.uid) { (post) in

        self.posts = self.posts.filter{ $0.id != post.id }
        self.users = self.users.filter{$0.id != post.userId }

        self.tableView.reloadData()

    }
}
func fetchUser(uid: String, completed: @escaping () -> Void) {
    API.User.observeUser(withId: uid, completion: {
        user in

        self.users.insert(user, at: 0)
        completed()
    })

}
}



 extension HomeViewController: UITableViewDataSource {



func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! HomeTableViewCell


    let post = posts[indexPath.row]
    let user = users[indexPath.row]
    cell.post = post
    cell.user = user
    cell.delegate = self
    return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return posts.count
}

}

extension HomeViewController : HomeTableViewCellDelegate {
func goToCommentViewController(postId:String) {
    performSegue(withIdentifier: "CommentSegue", sender: postId)
}
func goToProfileUserViewController(userId: String) {
    performSegue(withIdentifier: "Home_ProfileSegue", sender: userId)
}

func goToHashtag(tag: String) {
    performSegue(withIdentifier: "Home_Hashtag", sender: tag)
}
func goToLikesViewController(postId:String) {
    performSegue(withIdentifier: "LikeSegue", sender: postId)
}

}

那个 VC 就像 Instagram 上的提要,每个帖子的所有单元格都在其中。每个帖子都会计算喜欢它的用户,我想显示喜欢观察帖子的用户的点赞,而不是硬编码的帖子。

谢谢。 :)

【问题讨论】:

  • 我建议您获取新的访问令牌,因为您刚刚发布了它们以供所有人查看。这可以让他们访问您的数据库和存储。
  • @TristanBeaton 乍一看,我没有看到任何存在安全风险的值。你指的是什么价值观,你认为分享这些价值观会带来什么风险?
  • 我的印象是,使用访问令牌,人们可以绕过用户登录阶段并可能损坏您的数据库。
  • 我只希望它像 Instagram 中的一样,您可以点击点赞计数按钮并查看所有喜欢该帖子的人
  • @TristanBeaton 你是指photoUrl 属性中的访问令牌吗?这些值是 Firebase 为 Cloud Storage 文件生成的所谓下载 URL。下载 URL 是公开可读的,但如果您想授予文件的公共只读访问权限,则可以共享这些 URL。访问令牌只是为了使 URL 不可猜测。

标签: ios json swift firebase firebase-realtime-database


【解决方案1】:

这是我想出的。我使用您的 JSON 对其进行了测试,并且有效。它可能与您的原始代码有些不同,但它应该让您了解如何实现它。另外,fetchUser 函数似乎没用,所以我把它省略了,而 username_lowercase 没有意义,因为你可以在任何字符串上调用 .lowercased()。

import UIKit
import Firebase

class LikesViewController: UITableViewController {

    var postId: String! // add this var

    var users = Array<User>()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        self.loadUserLikes()
    }

    func loadUserLikes(){

        let api = UserApi()

        // changed this to var postId
        api.observeUserLikes(withPostId: postId) { (uids) in

            for uid in uids {

                api.observeUser(withId: uid, completion: { (user) in

                    if let currentUser = FIRAuth.auth()?.currentUser {

                        if uid == currentUser.uid {

                            self.users.insert(user, at: 0) // This will put the current user at the start of the array, so should be at top of table view.

                            self.tableView.reloadData()

                            return
                        }
                    }

                    self.users.append(user)

                    self.tableView.reloadData()
                })
            }
        }
    }

    // MARK: TableView Delegates
}

struct User {

    var uid: String

    var username: String

    var email: String

    var profileText: String

    var profileImageURL: String

    init?(uid: String, dict: Dictionary<String,String>) {

        guard

            let username = dict["username"],

            let email = dict["email"],

            let profileText = dict["profilText"],

            let profileImageURL = dict["profileImageUrl"]

        else {

            return nil
        }

        self.uid = uid

        self.username = username

        self.email = email

        self.profileText = profileText

        self.profileImageURL = profileImageURL
    }
}

class UserApi {

    var REF_USERS = FIRDatabase.database().reference().child("users")

    var REF_POST_USERS_LIKED = FIRDatabase.database().reference().child("LikesFromUsers")

    var REF_POST = FIRDatabase.database().reference().child("posts")

    func observeUser(withId uid: String,  completion: @escaping (User) -> Void) {

        REF_USERS.child(uid).observeSingleEvent(of: .value, with: { snapshot in

            guard let dict = snapshot.value as? Dictionary<String,String> else { return }

            if let user = User(uid: snapshot.key, dict: dict) {

                completion(user)

            } else {

                print("Incomplete User Data.")
            }
        })
    }

    func observeUsers(completion: @escaping (Array<User>) -> Void) {

        REF_USERS.observe(.value, with: { snapshot in

            guard let dict = snapshot.value as? Dictionary<String,Dictionary<String,String>> else { return }

            var users = Array<User>()

            for (key, value) in dict {

                if let user = User(uid: key, dict: value) {

                    guard let currentUser = FIRAuth.auth()?.currentUser else { return }

                    if user.uid != currentUser.uid {

                        users.append(user)
                    }

                } else {

                    print("Incomplete User Data.")
                }
            }

            completion(users)
        })
    }

    func observeUserLikes(withPostId id: String , completion: @escaping (Array<String>) -> Void) {

        REF_POST_USERS_LIKED.child(id).observeSingleEvent(of: .value, with: { snapshot in

            guard let dict = snapshot.value as? Dictionary<String,Bool> else { return }

            var users = Array<String>() // Array of user ids who liked the post.

            for (key, value) in dict {

                if value == true {

                    users.append(key)
                }
            }

            completion(users)
        })
    }

    // I've added this to get all the posts.
    func observePosts(completion: @escaping (Array<Post>) -> Void) {

        REF_POST.observe(.value, with: { snapshot in

            guard let dict = snapshot.value as? Dictionary<String,Dictionary<String,Any>> else { return }

            var posts = Array<Post>()

            for (key, value) in dict {

                if let post = Post(uid: key, dict: value) {

                    posts.append(post)

                } else {

                    print("Incomplete Post Data.")
                }
            }

            completion(posts)
        })
    }
}

这是我为测试 Likes View Controller 而制作的 Post View Controller。

struct Post {

    var uid: String

    var photoUrl: String

    var ratio: Double

    var score: Double

    var creationDate: Date

    init?(uid: String, dict: Dictionary<String,Any>) {

        guard

            let photoUrl = dict["photoUrl"] as? String,

            let ratio = dict["ratio"] as? Double,

            let score = dict["score"] as? Double,

            let creationDate = dict["creationDate"] as? TimeInterval

            else {

                return nil
        }


        self.uid = uid

        self.photoUrl = photoUrl

        self.ratio = ratio

        self.score = score

        self.creationDate = Date(timeIntervalSince1970: creationDate)
    }
}

struct Comment {

    var uid: String

    var user: User

    var comment: String
}

class PostsViewController: UITableViewController {

    var posts = Array<Post>()

    override func viewDidLoad() {
        super.viewDidLoad()

        let api = UserApi()

        api.observePosts { (posts) in

            self.posts = posts

            self.tableView.reloadData()
        }
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return self.posts.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        // Configure the cell...

        let post = self.posts[indexPath.row]

        cell.textLabel?.text = post.uid

        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        // Just for testing, I have it show the likes view controller when the cell is tapped. 
        // Although you will probably have this as a button, so just copy this code into the action.

        let post = posts[indexPath.row]

        guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "LikesViewController") as? LikesViewController else { return }

        vc.postId = post.uid

        self.navigationController?.pushViewController(vc, animated: true)
    }
}

这些屏幕截图仅显示帖子或用户的 uid,但您可以对其进行更改以显示所有必需的数据。

【讨论】:

  • 好的,谢谢你真的有效!现在我需要知道如何从每个特定帖子中获得喜欢该帖子的用户,因为它现在是硬编码的?而且我的应用程序在它想要​​配置关注按钮的地方崩溃了,我把它注释掉了,所以它起作用了,但这并不理想
  • 你是在问如何让这个视图控制器根据用户点击的帖子显示用户?如果是这种情况,您可以添加一些所有帖子都在的视图控制器的代码吗?
  • 当然我会在我的电脑上添加它
  • 我编辑了帖子!此外,我修复了以下错误,所以现在我如何从点击的帖子而不是硬编码的帖子中获取数据
  • 嘿,非常感谢,现在它工作得很好。但是现在我有一个不属于我们创建的方法的大错误。当我加载我的帖子时,它现在无限频繁地加载(我没有更改任何内容)并且我收到 maxretry 错误)你知道如何解决这个问题吗?你身边有没有发生过类似的事情?正如我所说,我什么都没改变,只是我的 score 函数现在被非常频繁地调用,直到它崩溃并且发生 maxRetry 错误
猜你喜欢
  • 2018-07-27
  • 2020-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多