how can I make firebase database data the data source for UICollection View?

后端 未结 1 541
温柔的废话
温柔的废话 2021-01-03 02:12

I want to change my model object datasource to firebase. I have a file that serves as the datasource for the UICollection view, homeViewController.swift . homeViewControlle

相关标签:
1条回答
  • 2021-01-03 02:41

    I hope this will get you started. It would be better to have the whole schema of the database, but I have made this based on what I could see from your screenshot. It also seems that having a separate BusinessCategory tree is not needed since you have the category type for each business in the Business tree, although that is completely up to you.

    If you want to provide a more complete screenshot of your database (just something that shows the keys and data types), I would be happy to modify this code.

    Since I don't know how you update your collection view, I have made it so it returns a Dictionary where the key is the category and the value is an array of bussinesses of that category. This should be an easy format if you are using sections in your collection view.

    With regards to the typealias FirebaseRootDictionary, it might need to be modified as I was guessing on what your database schema was.

    If you have any questions or problems with this code just put a comment beneath, and I'll try to fix it.

    So to get your data:

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        Business.getBusinesses { (businesses) in
    
            print(businesses)
        }
    }
    

    Then inside that closure have it update the collection view.

    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)
            })
        }
    }
    

    Edit:

    So for the view, you have a tableview with one cell per section/category. The cell has a collection view, which has a collection view cell with a image view and label. So here I have a table view controller that will handle all that.

    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
        }
    }
    

    The table view cell file.

    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
        }
    }
    

    This is the collection view 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)
        }
    }
    

    Here is a screenshot of the test database I made.

    0 讨论(0)
提交回复
热议问题