【问题标题】:how can I make firebase database data the data source for UICollection View?如何使 firebase 数据库数据成为 UICollectionView 的数据源?
【发布时间】:2026-02-09 12:25:01
【问题描述】:

我想将我的模型对象数据源更改为 firebase。 我有一个文件作为 UICollection 视图的数据源 homeViewController.swift 。 homeViewController.swift 是一个垂直排列的collectionViewCell,每个cell都有自己水平排列的collectionViewcell。

这是 models.swift 文件

import UIKit
import Firebase

class BusinessCategory: NSObject {

var name: String?
var featurebusiness: [SampleBusinesses]?
var type: String?


static func sampleBusinessCategories() -> [BusinessCategory] {
 let FastfoodCategory = BusinessCategory()
    FastfoodCategory.name = "Fast Food"
    var topFastFood = [SampleBusinesses]()

    let FastfoodApp = SampleBusinesses()
    FastfoodApp.name = "Papa Johns"
    FastfoodApp.imageName = "PJ"
    topFastFood.append(FastfoodApp)
    FastfoodCategory.featurebusiness = topFastFood


    let MobilePhoneCategory = BusinessCategory()
    MobilePhoneCategory.name = "Mobile Phones"
    var topMobilePhoneProvider = [SampleBusinesses]()
    //logic
    let MobilePhoneApp = SampleBusinesses()
    MobilePhoneApp.name = "Verizon"
    MobilePhoneApp.imageName = "verizon"
    topMobilePhoneProvider.append(MobilePhoneApp)
    MobilePhoneCategory.featurebusiness = topMobilePhoneProvider

    return [ FastfoodCategory, MobilePhoneCategory ]

我想更改目标文件,以便它由我的 firebase 数据库 (BusinessCategories) 填充。我尝试了很多选择,但我无法弄清楚。如何将我的目标文件从物理输入的数据更改为 Firebase 数据?

如果有帮助,这是我的 Firebase 数据。例如,“银行”将是类别名称,单元格将由银行下的所有条目填充。

更新: 我想要实现的类似于 Appstore UI,即不同类别的应用程序,每个类别都是一个带有水平滚动的集合视图。在我的应用程序中,企业位于 firebase 中列出的不同类别中,并且每个类别都可以水平滚动。

如何在下面更新我的集合视图属性?

 override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CategoryCell

        cell.businessCategory = businessCategories?[indexPath.item]

    return cell
}

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    if let count = businessCategories?.count{

        return count 
    }
    return 0
}

【问题讨论】:

  • 不幸的是,我对Firebase 一点也不熟悉。我假设他们有 API 代码示例,这些示例应该如何将您的数据放入您的对象中(所以我建议深入研究他们的文档)。我现在无法真正研究它,尽管我很乐意尝试帮助你。
  • 好的,谢谢,我会很感激的

标签: swift firebase firebase-realtime-database uicollectionview nsobject


【解决方案1】:

我希望这能让你开始。拥有数据库的整个架构会更好,但我是根据从您的屏幕截图中看到的内容制作的。似乎也不需要单独的 BusinessCategory 树,因为您在业务树中拥有每个业务的类别类型,尽管这完全取决于您。

如果您想提供更完整的数据库屏幕截图(仅显示键和数据类型的内容),我很乐意修改此代码。

因为我不知道你如何更新你的集合视图,所以我做了它,所以它返回一个字典,其中键是类别,值是该类别的业务数组。如果您在集合视图中使用部分,这应该是一种简单的格式。

关于 typealias FirebaseRootDictionary,它可能需要修改,因为我猜测您的数据库架构是什么。

如果您对此代码有任何疑问或问题,请在下方发表评论,我会尽力修复它。

所以要获取您的数据:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    Business.getBusinesses { (businesses) in

        print(businesses)
    }
}

然后在该闭包中更新集合视图。

import Foundation
import Firebase

final class Business : NSObject {

    typealias FirebaseRootDictionary = Dictionary<String,Dictionary<String,Dictionary<String,String>>>

    var name: String

    var category: String

    var email: String

    var imageUrl: String

    override var description: String {

        return "Business(name: \"\(name)\", category: \"\(category)\", email: \"\(email)\", imageUrl: \"\(imageUrl)\")"
    }

    init(name:String, category:String, email:String, imageUrl:String) {

        self.name = name

        self.category = category

        self.email = email

        self.imageUrl = imageUrl
    }

    class func getBusinesses(completionHandler:@escaping (_ businesses: BusinessesDictionary)->()) { // -> [Business]

        let ref = FIRDatabase.database().reference().child("BusinessCategories")

        var businesses = BusinessesDictionary()

        ref.observeSingleEvent(of: .value, with: { (snapshot) in

            guard let value = snapshot.value as? FirebaseRootDictionary else { return }

            let categories = value.keys.sorted()

            var arr = [Business]() // Array of businesses for category

            for cat in categories {

                guard let data = value[cat] else { continue }

                let businessKeys = data.keys.sorted()

                for key in businessKeys {

                    guard let businessData = data[key] else { continue }

                    guard let name = businessData["BusinessName"], let category = businessData["Category"], let email = businessData["email"], let imageUrl = businessData["imageUrl"] else { continue }

                    let business = Business(name: name, category: category, email: email, imageUrl: imageUrl)

                    arr.append(business)
                }

                businesses[cat] = arr

                arr.removeAll()
            }

            completionHandler(businesses)
        })
    }
}

编辑:

因此,对于视图,您有一个表格视图,每个部分/类别有一个单元格。该单元格具有一个集合视图,该集合视图具有一个带有图像视图和标签的集合视图单元格。所以这里我有一个表格视图控制器来处理所有这些。

import UIKit

typealias BusinessesDictionary = Dictionary<String,[Business]> // I have moved this typealias to here instead of inside the Business Model.

class TableViewController: UITableViewController {

    var tableData = BusinessesDictionary()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.register(CategoryCell.self, forCellReuseIdentifier: "cell")

        self.tableView.allowsSelection = false

        Business.get { (businesses) in

            self.tableData = businesses

            self.tableView.reloadData()
        }
    }

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

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {

        return self.tableData.keys.count
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

        let category = self.tableData.keys.sorted()[section]

        return category
    }

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

        return 1
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CategoryCell else { return UITableViewCell() }

        // Configure the cell...

        let category = self.tableData.keys.sorted()[indexPath.section]

        guard let businesses = self.tableData[category] else { return UITableViewCell() }

        cell.businesses = businesses

        return cell
    }

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

        return 120
    }
}

表格视图单元格文件。

class CategoryCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {

    var collectionView: UICollectionView!

    var businesses = [Business]()

    override func layoutSubviews() {

        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()

        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) // You may wan to change this as this is the spacing between cells

        layout.itemSize = CGSize(width: 100, height: 120) // You may wan to change this as this is the cell size

        layout.scrollDirection = .horizontal

        collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: layout)

        collectionView.topAnchor.constraint(equalTo: self.topAnchor)

        collectionView.leftAnchor.constraint(equalTo: self.leftAnchor)

        collectionView.rightAnchor.constraint(equalTo: self.rightAnchor)

        collectionView.bottomAnchor.constraint(equalTo: self.bottomAnchor)

        collectionView.dataSource = self

        collectionView.delegate = self

        collectionView.register(BusinessCell.self, forCellWithReuseIdentifier: "businessCell")

        collectionView.backgroundColor = .white

        self.addSubview(collectionView)
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return businesses.count
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {

        return 1
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "businessCell", for: indexPath) as? BusinessCell else { return UICollectionViewCell() }

        // Configure the cell

        let business = self.businesses[indexPath.row]

        cell.nameLabel.text = business.name

        cell.imageView.image = UIImage(named: business.imageUrl)

        return cell
    }
}

这是集合视图单元格。

class BusinessCell: UICollectionViewCell {

    var imageView: UIImageView!

    var nameLabel: UILabel!

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

        imageView = UIImageView(frame: CGRect(x: 20, y: 20, width: 60, height: 60))

        imageView.contentMode = .scaleAspectFit

        nameLabel = UILabel(frame: CGRect(x: 0, y: 90, width: 100, height: 30))

        nameLabel.font = UIFont.systemFont(ofSize: 11)

        nameLabel.textAlignment = .center

        self.addSubview(imageView)

        self.addSubview(nameLabel)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

这是我做的测试数据库的截图。

【讨论】:

  • 感谢您的帮助,我现在正在实施您的代码。我正在尝试创建一个类似于 Appstore 的用户界面,其中包含各自类别的企业。
  • 如何更新我刚刚发布的收藏视图属性?
  • 哇..感谢您的大量工作。我没有使用故事板,一切都是以编程方式完成的。这将如何影响您的代码建议
  • 非常感谢。我非常感谢耐心和辛勤工作