【问题标题】:How to pull users from database and list them in a table view using firebase?如何使用firebase从数据库中提取用户并在表视图中列出它们?
【发布时间】:2017-12-27 21:40:53
【问题描述】:

我正在使用 firebase 制作 iOS 应用。我想检索数据库中的所有用户并在表格视图中显示他们的姓名和个人资料图片。这是我的TableViewCell 代码:

import UIKit
import FirebaseDatabase
import FirebaseAuth
import SDWebImage

class HomeTableViewCell: UITableViewCell {


    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var profileImageView: UIImageView!
    @IBOutlet weak var likeImageView: UIImageView!
    @IBOutlet weak var messageImageView: UIImageView!
    @IBOutlet weak var likeCountButton: UIButton!

    var homeVC: HomeViewController?
    var postReference: DatabaseReference!

    var post: UserFile?{
        didSet {
            updateView()
        }
    }

    var user: UserFile? {
        didSet {
            updateUserInfo()
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        nameLabel.text = ""

        let berryTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleLikeTap))

        likeImageView.addGestureRecognizer(berryTapGesture)
        likeImageView.isUserInteractionEnabled = true

    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

    func updateView() {
        if let photoURL = post?.picURL {
            profileImageView.sd_setImage(with: URL(string: photoURL))
        }

        API.Post.REF_POSTS.child(post!.id!).observeSingleEvent(of: .value, with: { postSnapshot in
            if let postDictionary = postSnapshot.value as? [String:Any] {
                let post = UserFile.transformPost(postDictionary: postDictionary, key: postSnapshot.key)
                self.updateLike(post: post)
            }
        })
        API.Post.REF_POSTS.child(post!.id!).observe(.childChanged, with: { snapshot in
            if let value = snapshot.value as? Int {
                self.likeCountButton.setTitle("\(value) berries", for: .normal)
            }
        })
    }

    func updateLike(post: UserFile) {
        let imageName = post.berries == nil || !post.isBerried! ? "berry" : "berrySelected"
        likeImageView.image = UIImage(named: imageName)

        // display a message for berries
        guard let count = post.berryCount else {
            return
        }

        if count != 0 {
            likeCountButton.setTitle("\(count) berries", for: .normal)
        } else if post.berryCount == 0 {
            likeCountButton.setTitle("Be the first to Like this", for: .normal)
        }
    }

    func incrementberries(forReference ref: DatabaseReference) {
        ref.runTransactionBlock({ (currentData: MutableData) -> TransactionResult in
            if var post = currentData.value as? [String : AnyObject], let uid = Auth.auth().currentUser?.uid {
                var berries: Dictionary<String, Bool>
                berries = post["berries"] as? [String : Bool] ?? [:]
                var likeCount = post["berryCount"] as? Int ?? 0
                if let _ = berries[uid] {
                    // Unlike the post and remove self from stars
                    likeCount -= 1
                    berries.removeValue(forKey: uid)
                } else {
                    // Like the post and add self to stars
                    likeCount += 1
                    berries[uid] = true
                }
                post["berryCount"] = likeCount as AnyObject?
                post["berries"] = berries as AnyObject?

                currentData.value = post

                return TransactionResult.success(withValue: currentData)
            }
            return TransactionResult.success(withValue: currentData)
        }) { (error, committed, snapshot) in
            if let error = error {
                print(error.localizedDescription)
            }

            if let postDictionary = snapshot?.value as? [String:Any] {
                let post = UserFile.transformPost(postDictionary: postDictionary, key: snapshot!.key)
                self.updateLike(post: post)
            }
        }
    }

    func handleLikeTap() {
        postReference = API.Post.REF_POSTS.child(post!.id!)
        incrementberries(forReference: postReference)
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        profileImageView.image = UIImage(named: "industribune-default-no-profile-pic")
    }

    func updateUserInfo() {
        nameLabel.text = user?.username
        if let photoURL = user?.profileImageURL {
            profileImageView.sd_setImage(with: URL(string: photoURL), placeholderImage: UIImage(named: "industribune-default-no-profile-pic"))
        }
    }


}

我正在我的HomeViewController 上显示此单元格:

import UIKit
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage
import Firebase

class HomeViewController: UIViewController {


    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!

    var posts = [UserFile]()
    var users = [UserFile]()

    override func viewDidLoad() {
        super.viewDidLoad()
        // for performance set an estimated row height
        tableView.estimatedRowHeight = 1
        // but also request to dynamically adjust to content using AutoLayout
        tableView.rowHeight = UITableViewAutomaticDimension

        //tableView.delegate = self
        tableView.dataSource = self

        loadPosts()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func loadPosts() {
        activityIndicatorView.startAnimating()

        API.User.observePosts { (newPost) in
            guard let userID = newPost.uid else { return }
            self.fetchUser(uid: userID, completed: {
                // append the new Post and Reload after the user
                // has been cached
                self.posts.append(newPost)
                self.activityIndicatorView.stopAnimating()
                self.tableView.reloadData()
            })
        }
    }

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

        API.User.observeUser(withID: uid) { user in
            self.users.append(user)

            completed()
        }
    }


}

extension HomeViewController: UITableViewDataSource {

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

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

        cell.post = posts[indexPath.row]
        cell.user = users[indexPath.row]
        cell.homeVC = self

        return cell
    }

}

我的项目中有很多疯狂的事情发生,所以如果您有任何问题,请告诉我以及我做错了什么。如果理解起来太复杂,我已经准备好删除所有内容并重新开始。

老实说,我确实认为我遵循了所有准则来提出问题,所以不喜欢关闭这个问题或其他什么。

【问题讨论】:

    标签: ios swift firebase


    【解决方案1】:

    这是很多代码。试试这个超级简化的例子。为此,用户节点仅将名称存储为子节点,但它也可以包含图像、电子邮件、地址等。

    示例用户节点

    users
      uid_0:
         name: "Bert"
      uid_1:
         name: "Ernie"
    

    还有一些代码

    var usersArray = [ [String: Any] ]()  //an array of dictionaries.
    
    class ViewController: UIViewController {
        //set up firebase references here
       override func viewDidLoad() {
            super.viewDidLoad()
    
            let usersRef = self.ref.child("users")
            usersRef.observeSingleEvent(of: .value, with: { snapshot in
             for child in snapshot.children {
                  let snap = child as! DataSnapshot
                  let userDict = snap.value as! [String: Any]
                  self.usersArray.append(userDict)
             }
             self.tableView.reloadData()
       })
    

    和 tableView 委托方法

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.usersArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
    
        let userDict = self.usersArray[indexPath.row]
        cell.text = userDict["name"] as! String
        //cell.imge = userDict["image"] etc etc
    
        return cell
    }
    

    现在……说了这么多。这是 UserClass 对象数组而不是字典的完美用途。

    这是一个起点......

    class UserClass {
       var name = ""
       var image = ""
    
       func init(snap: DataSnapshot) {
         //populate the vars from the snapshot
       }
    }
    
    var userClassArray = [UserClass]()
    

    请勿复制粘贴,因为可能存在拼写错误,但它应该为您指明正确的方向。

    【讨论】:

    • let userDict = child.value as! [String: Any] 一直给我一个错误?我是 Swift 的初学者,所以任何帮助都将不胜感激!
    • @B.Pandey 哎呀。遗漏了一些代码 - 它已被更新。这个想法是逐个迭代快照中返回的子节点。每个迭代对象(子对象)都是一个枚举器对象。我们将其转换为数据快照(让 snap = child as!DataSnapshot),以便我们可以访问它的值。然后将该值转换为字典以访问各个元素。这可以用更少的代码行来编写,但我把它写得很冗长以使概念更清晰。
    • 最后几行以class UserClass {开头的代码我应该把它放在一个新的Swift文件中还是什么?就像基本上我在问我应该把最后几行代码放在哪里?
    • @B.Pandey 如答案中所述,您可以将它们包装到 UserClass 中,而不是使用字典来处理您的数据,这将是更简洁的代码。如果您对 Swift 中的 implementing classes 感到满意,那么这就是您要走的路。如果没有,请暂时使用字典。
    • 我不知道为什么这个答案不是被选中的,并且有 0 票。 +1:对我来说非常完美,几乎不需要调整。特维姆!!我一直在寻找这个答案将近一个星期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-16
    • 2013-01-24
    • 2022-09-23
    • 1970-01-01
    • 2017-04-09
    • 2020-10-12
    相关资源
    最近更新 更多