首页 > 解决方案 > 从 firebase 检索信息并在 UICollectionView 中设置为图像和标签

问题描述

我正在尝试检索一些存储在 firebase 中的数据,并允许该信息显示在集合视图中。如profileImageUrl、姓名标签和电子邮件标签。

我曾尝试阅读 firebase 和苹果网站上的文档,但由于某种原因,我的代码返回纯文本。我没有收到任何错误,但我的代码没有按预期运行。当我转到我的应用程序的配置文件视图时,显示的唯一文本是我以编程方式放置的占位符。

let profileImageView: UIImageView = {
    let imageView = UIImageView()
    imageView.image = UIImage(named: "users")
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFill
    return imageView
}()
let nameLabel: UILabel = {
 let label = UILabel()
    label.text = "User's Name"
    label.font = UIFont.boldSystemFont(ofSize: 18)
    label.textColor = GREEN_Theme
    return label
}()
let uidLabel: UILabel = {
    let label = UILabel()
    label.text = "User's uid"
    label.font = UIFont.boldSystemFont(ofSize: 16)
    label.textColor = GREEN_Theme
    return label
}()
let emailLabel: UILabel = {
    let label = UILabel()
    label.text = "User's email"
    label.font = UIFont.boldSystemFont(ofSize: 16)
    label.textColor = GREEN_Theme
    return label
}()
override init(frame: CGRect) {
    super.init(frame: frame)

    setupView()
}

func setupView() {
if Auth.auth().currentUser != nil {
    guard let uid = Auth.auth().currentUser?.uid else {
        return }
    Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
        guard let dictionary = snapshot.value as? [String : Any] else {
            return }
       let user = CurrentUser(uid: uid, dictionary: dictionary)
        self.uidLabel.text = uid
        self.nameLabel.text = user.name
        self.emailLabel.text = user.email
       self.profileImageView.loadImageUsingCacheWithUrlString(user.profileImageUrl)
    }, withCancel: { (err) in
        print("attempting to load information")
      })  
       self.addSubview(profileImageView)
       self.addSubview(nameLabel)
       self.addSubview(emailLabel)
       self.addSubview(uidLabel)
     profileImageView.anchors(top: topAnchor, topPad: 125, bottom: bottomAnchor, bottomPad: 75, left: leftAnchor, leftPad: 20, right: rightAnchor, rightPad: 250, height: 20, width: 20)
    nameLabel.anchors(top: profileImageView.bottomAnchor, topPad: -50, bottom: bottomAnchor, bottomPad: 0, left: profileImageView.leftAnchor, leftPad: 0, right: rightAnchor, rightPad: 0, height: 20, width: 20)
    emailLabel.anchors(top: nameLabel.bottomAnchor, topPad: -80, bottom: bottomAnchor, bottomPad: 0, left: profileImageView.leftAnchor, leftPad: 0, right: rightAnchor, rightPad: 125, height: 20, width: 20)
    uidLabel.anchors(top: emailLabel.bottomAnchor, topPad: -40, bottom: bottomAnchor, bottomPad: 0, left: profileImageView.leftAnchor, leftPad: 0, right: rightAnchor, rightPad: 0, height: 20, width: 20)
    profileImageView.layer.zPosition = 10
    nameLabel.layer.zPosition = 10
    emailLabel.layer.zPosition = 10
    profileImageView.layer.borderWidth = 2.0
    profileImageView.layer.cornerRadius = 50
    profileImageView.layer.borderWidth = 2.0
    profileImageView.layer.borderColor = UIColor.white.cgColor
    profileImageView.layer.masksToBounds = true

 }
}

如果有人可以帮助批评我所拥有的东西,并帮助我展示正确的实现是什么样的,我将非常感激。任何和所有的帮助将不胜感激

标签: swiftfirebasefirebase-realtime-databaseuicollectionview

解决方案


有几件事是不正确的。

  1. 您的手机不应该是负责下载或进行任何网络调用的人,将其留给viewController所有网络调用的单独处理程序,甚至更好。
  2. Firebase 是异步的,因此当您下载数据时,所有视图都已设置并显示,这就是您只看到占位符的原因。
  3. 您有很多用于检查选项的冗余代码,这不是什么大问题,但也不需要。

您真的应该考虑更改所有这些代码并将不同的任务分离到不同的处理程序。例如,您可以创建一个单独的类来控制对 Firebase 的所有调用并返回带有完成块的值,从 viewController 或 collectionView 本身要求网络处理程序为您提供所需的数据,将此数据传递给单元格并让单元格显示数据,单元格应该只显示数据,而不是下载或请求网络请求。我无法为您编写完整的示例,但我认为如果您在 google 中四处逛逛,您会发现很多非常好的示例和教程。

无论如何,只是为了让您开始,以便您查看代码中的错误,这里有一个快速修复它。即使它有效,也不要理所当然地认为一切都是固定的。你真的应该重构所有代码并分离不同的任务。希望这至少可以帮助您解决在单元格中显示下载数据的问题。

let profileImageView: UIImageView = {
    let imageView = UIImageView()
    imageView.image = UIImage(named: "users")
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFill
    return imageView
}()
let nameLabel: UILabel = {
    let label = UILabel()
    label.text = "User's Name"
    label.font = UIFont.boldSystemFont(ofSize: 18)
    label.textColor = GREEN_Theme
    return label
}()
let uidLabel: UILabel = {
    let label = UILabel()
    label.text = "User's uid"
    label.font = UIFont.boldSystemFont(ofSize: 16)
    label.textColor = GREEN_Theme
    return label
}()
let emailLabel: UILabel = {
    let label = UILabel()
    label.text = "User's email"
    label.font = UIFont.boldSystemFont(ofSize: 16)
    label.textColor = GREEN_Theme
    return label
}()


// Here you add a variable that is observed for SET, once a set happens bind() will be called and the views will be updated.
var currentUser : CurrentUser? {
    didSet {
        self.bind()
    }
}

override init(frame: CGRect) {
    super.init(frame: frame)
    //...
}


// setupView() should only add the UI appearance, and in this case it is calling firebase and setting currentUser, but it should not do that. This is what you have to refactor.
func setupView() {
    self.addSubview(profileImageView)
    self.addSubview(nameLabel)
    self.addSubview(emailLabel)
    self.addSubview(uidLabel)
    profileImageView.anchors(top: topAnchor, topPad: 125, bottom: bottomAnchor, bottomPad: 75, left: leftAnchor, leftPad: 20, right: rightAnchor, rightPad: 250, height: 20, width: 20)
    nameLabel.anchors(top: profileImageView.bottomAnchor, topPad: -50, bottom: bottomAnchor, bottomPad: 0, left: profileImageView.leftAnchor, leftPad: 0, right: rightAnchor, rightPad: 0, height: 20, width: 20)
    emailLabel.anchors(top: nameLabel.bottomAnchor, topPad: -80, bottom: bottomAnchor, bottomPad: 0, left: profileImageView.leftAnchor, leftPad: 0, right: rightAnchor, rightPad: 125, height: 20, width: 20)
    uidLabel.anchors(top: emailLabel.bottomAnchor, topPad: -40, bottom: bottomAnchor, bottomPad: 0, left: profileImageView.leftAnchor, leftPad: 0, right: rightAnchor, rightPad: 0, height: 20, width: 20)
    profileImageView.layer.zPosition = 10
    nameLabel.layer.zPosition = 10
    emailLabel.layer.zPosition = 10
    profileImageView.layer.borderWidth = 2.0
    profileImageView.layer.cornerRadius = 50
    profileImageView.layer.borderWidth = 2.0
    profileImageView.layer.borderColor = UIColor.white.cgColor
    profileImageView.layer.masksToBounds = true

    guard let user = Auth.auth().currentUser else { return }
    let uid = user.uid
    let reference = Database.database().reference().child("users").child(uid)
    reference.observeSingleEvent(of: .value, with: { (snapshot) in
        guard let dictionary = snapshot.value as? [String : Any] else { return }
        self.currentUser = CurrentUser(uid: uid, dictionary: dictionary)
    }, withCancel: { (err) in
        print("attempting to load information")
    })
}

// This is the method that updates the cell views.
func bind() {
    self.uidLabel.text = currentUser.uid
    self.nameLabel.text = currentUser.name
    self.emailLabel.text = currentUser.email
    self.profileImageView.loadImageUsingCacheWithUrlString(currentUser.profileImageUrl)
}

推荐阅读