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 . homeViewController.swift is a vertically arranged collectionViewCell and each cell has its own horizontally arranged collectionViewcell.
This is the models.swift file
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 ]
I want to change the object file so that it is populated by my firebase database (BusinessCategories). I have tried many options but I have not been able to figure it out. How do I change my object file from the physically entered data to firebase data?
Here is my Firebase data if it helps. For example "Banks" will be category name and the cell will be populated by all the entries under banks.
Update: What I am trying to achieve is similar to Appstore UI that different categories of apps and each category is a collection view with an horizontal scroll. In my application, Businesses are in different categories listed in firebase and each category is scrollable horizontally.
how do I update my collection view attributes below?
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
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With