how do I fetch data from the Firestore? - ios

I'm trying to pass data onto my tableview, from my cloud firestore but it just not able to retrieve the data and post it on the tableview and so far most of of my attempts have failed. since I'm transition from real-time database to Firestore.
I've used multiple resources on stack, restructured my code multiple times and have now come down to this
here is also an image of my collection in Firestore firestore collection
import Foundation
class ProductList {
var id: String?
var name: String?
var dispensaryName: String?
var category: String?,
var brand: String?
var imageUrl: String?
init(id: String?,
name: String?,
dispensaryName: String?,
brand: String?,
category: String?,
imageUrl: String?) {
self.id = id
self.name = name
self.dispensaryName = dispensaryName
self.brand = brand
self.category = category,
self.imageUrl = imageUrl
}
}
import UIKit
class ProductListCell: UITableViewCell {
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var dispensaryName: UILabel!
#IBOutlet weak var productName: UILabel!
#IBOutlet weak var categoryLabel: UILabel!
#IBOutlet weak var categoryStrain: UILabel!
}
import UIKit
import Firebase
import FirebaseFireStore
class ProductListController: UIViewController {
#IBOutlet weak var productListTableView: UITableView!
#IBOutlet weak var menuButton: UIBarButtonItem!
var dbRef: DatabaseReference!
var productSetup: [ProductList] = []
override func viewDidLoad() {
super.viewDidLoad()
productListTableView.dataSource = self
productListTableView.delegate = self
self.productListTableView.rowHeight = UITableView.automaticDimension
self.productListTableView.estimatedRowHeight = 363
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
dbRef = Database.database().reference().child("products");
//observing the data changes
dbRef.observe(DataEventType.value, with: { (snapshot) in
//if the reference have some values
if snapshot.childrenCount > 0 {
//clearing the list
self.productSetup.removeAll()
//iterating through all the values
for producting in snapshot.children.allObjects as! [DataSnapshot] {
//getting values
let productObject = producting.value as? [String: AnyObject]
let id = productObject?["id"]
let name = productObject?["name"]
let dispensaryName = productObject?["dispensaryName"]
let category = productObject?["category"]
let strain = productObject?["strain"]
let imageUrl = productObject?["imageUrl"]
//creating artist object with model and fetched values
let massProducts = ProductList(id: id as! String?,
name: name as! String?,
dispensaryName: dispensaryName as! String?,
category: category as! String?,
strain: strain as! String?,
imageUrl: imageUrl as! String?)
//appending it to list
self.productSetup.append(massProducts)
}
//reloading the tableview
print(self.productSetup)
self.productListTableView.reloadData()
}
})
}
}
extension ProductListController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as!
ProductListCell
let production: ProductList
production = productSetup[indexPath.row]
cell.productName.text = "\(String(describing: production.brand)): \(String(describing: production.name))"
cell.dispensaryName.text = production.dispensaryName
cell.categoryLabel.text = production.category
cell.productImage.text = production.imageUrl
return cell
}
}

I have reformatted the code quickly to make it easier to understand but it could be one of many things;
Check user authenticated with firebase on the device.
Ensure you have setup security settings correctly to allow reads in firebase.
Reformatted Code
ProductListController.swift
import Firebase
class ProductListController: UIViewController {
#IBOutlet weak var productListTableView: UITableView!
#IBOutlet weak var menuButton: UIBarButtonItem!
var productSetup = [ProductList]()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
productListTableView.dataSource = self
productListTableView.delegate = self
productListTableView.rowHeight = UITableView.automaticDimension
productListTableView.estimatedRowHeight = 363
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
fetchProducts { (products) in
self.productSetup = products
self.productListTableView.reloadData()
}
}
func fetchProducts(_ completion: #escaping ([ProductList]) -> Void) {
let ref = Firestore.firestore().collection("products")
ref.addSnapshotListener { (snapshot, error) in
guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
return
}
completion(snapshot.documents.compactMap( {ProductList(dictionary: $0.data())} ))
}
}
}
extension ProductListController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as?
ProductListCell else { return UITableViewCell() }
cell.configure(withProduct: productSetup[indexPath.row])
return cell
}
}
ProductListCell.swift
import Firebase
class ProductListCell: UITableViewCell {
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var dispensaryName: UILabel!
#IBOutlet weak var productName: UILabel!
#IBOutlet weak var categoryLabel: UILabel!
#IBOutlet weak var categoryStrain: UILabel!
func configure(withProduct product: ProductList) {
productName.text = "\(String(describing: product.brand)): \(String(describing: product.name))"
dispensaryName.text = product.dispensaryName
categoryLabel.text = product.category
fetchImage(withURL: product.imageUrl ) { (image) in
productImage.image = image
}
}
func fetchImage(withURL url: String, _ completion: #escaping (UIImage) -> Void) {
let ref = Storage.storage().reference(forURL: url)
ref.getData(maxSize: 1 * 1024 * 1024) { (data, error) in
guard error == nil, let imageData = data, let image = UIImage(data: imageData) else {
return
}
completion(image)
}
}
}
ProductList.swift
class ProductList {
var id: String
var name: String
var dispensaryName: String
var category: String
var brand: String
var imageUrl: String
init(id: String, name: String, dispensaryName: String, brand: String, category: String, imageUrl: String) {
self.id = id
self.name = name
self.dispensaryName = dispensaryName
self.brand = brand
self.category = category
self.imageUrl = imageUrl
}
convenience init(dictionary: [String : Any]) {
let id = dictionary["id"] as? String ?? ""
let name = dictionary["name"] as? String ?? ""
let dispensaryName = dictionary["dispensaryName"] as? String ?? ""
let brand = dictionary["brand"] as? String ?? ""
let category = dictionary["category"] as? String ?? ""
let imageUrl = dictionary["imageUrl"] as? String ?? ""
self.init(id: id, name: name, dispensaryName: dispensaryName, brand: brand, category: category, imageUrl: imageUrl)
}
}
I Hope you found this helpful.

Related

iOS / Swift - Appending a filter to retrieving data from Firebase

What I got so far is a tableView and custom Cells about hookah tobacco. Those include an image, name, brand and ID. Now what I try to reach is basically a tableview that contains only the cells with attributes based on a "filter". For example the tableView that appears at the beginning has only the following two settings to make it simple: PriceRange and BrandName. At the first time loading the tableView those are PriceRange: 0 - 100 and Brands: all brands. Then imagine a user restricting those like 0 - 15 Euros and only brand called "7 Days". How exactly would I do that with reloading the tableView?
import UIKit
import Firebase
class ShopViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var button_filter: UIBarButtonItem!
#IBOutlet weak var searchBar_shop: UISearchBar!
#IBOutlet weak var view_navigator: UIView!
#IBOutlet weak var tableView_shop: UITableView!
var ShopCells: [ShopCell] = []
var databaseRef: DatabaseReference!
var storageRef: StorageReference!
override func viewDidLoad() {
super.viewDidLoad()
self.databaseRef = Database.database().reference()
self.storageRef = Storage.storage().reference()
createArray() { shopCells in
for item in shopCells {
self.ShopCells.append(item)
}
DispatchQueue.main.async {
self.tableView_shop.reloadData()
}
}
self.navigationItem.title = "Shop"
self.tableView_shop.delegate = self
self.tableView_shop.dataSource = self
self.searchBar_shop.delegate = self
self.searchBar_shop.barTintColor = UIColor(hexString: "#1ABC9C")
self.view_navigator.backgroundColor = UIColor(hexString: "#1ABC9C")
self.tableView_shop.separatorColor = UIColor.clear
self.searchBar_shop.isTranslucent = false
self.searchBar_shop.backgroundImage = UIImage()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ShopViewController.viewTapped(gestureRecognizer:)))
view.addGestureRecognizer(tapGesture)
}
#objc func viewTapped(gestureRecognizer: UITapGestureRecognizer) {
view.endEditing(true)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.searchBar_shop.resignFirstResponder()
}
func createArray(completion: #escaping ([ShopCell]) -> () ) {
var tempShopCells: [ShopCell] = []
let rootRef = Database.database().reference()
let query = rootRef.child("tobaccos").queryOrdered(byChild: "name")
query.observeSingleEvent(of: .value) { (snapshot) in
let dispatchGroup = DispatchGroup()
for child in snapshot.children.allObjects as! [DataSnapshot] {
let value = child.value as? [String: Any];
let name = value?["name"] as? String ?? "";
let brand = value?["brand"] as? String ?? "";
let iD = value?["iD"] as? String ?? "";
dispatchGroup.enter()
let imageReference = Storage.storage().reference().child("tobaccoPictures").child("\(iD).jpg")
imageReference.getData(maxSize: (1 * 1024 * 1024)) { (data, error) in
if let _error = error{
print(_error)
} else {
if let _data = data {
let image: UIImage! = UIImage(data: _data)
tempShopCells.append(ShopCell(productName: name, brandName: brand, productImage: image, iD: iD))
}
}
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
completion(tempShopCells)
}
}
}
}
extension ShopViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.ShopCells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let shopCell = ShopCells[indexPath.row]
let cell = tableView_shop.dequeueReusableCell(withIdentifier: "ShopCell") as! ShopTableViewCell
cell.setShopCell(shopCell: shopCell)
return cell
}
}

Error: Cannot assign value of type 'String?' to type 'String?.Type'

I've got a couple a problem with this code. Here's my code and I don't understand why there is an error line 61 with cell.userID = self.user[indexPath.row].userID it says : Cannot assign value of type String? to type String?.Type. It's probably because in line 36 : if let uid = value["profilepicture.userID"] as? String. userID is in Firebase a child of profile picture but I don't know how to write that inside of value[]. Thanks for your answers.
// TableViewCell.swift
import UIKit
class FriendsTableViewCell: UITableViewCell {
#IBOutlet weak var userImage: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
var userID = String?.self
}
// ViewController.swift
import UIKit
import Firebase
class FriendsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableview: UITableView!
var user = [User]()
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func retrieveUsers() {
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { DataSnapshot in
let users = DataSnapshot.value as! [String: AnyObject]
self.user.removeAll()
for (_, value) in users{
//let uid = Auth.auth().currentUser!.uid
if let uid = value["profilepicture.userID"] as? String{
if uid != Auth.auth().currentUser!.uid {
let userToShow = User()
if let fullName = value["username"] as? String , let imagePath = value["profilepicture.photoURL"] as? String {
userToShow.username = fullName
userToShow.imagePath = imagePath
userToShow.userID = uid
self.user.append(userToShow)
}
}
}
}
})
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableview.dequeueReusableCell(withIdentifier: "FriendsTableViewCell", for: indexPath) as! FriendsTableViewCell
cell.nameLabel.text = self.user[indexPath.row].username
cell.userID = self.user[indexPath.row].userID
cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return user.count ?? 0
}
}
extension UIImageView{
func downloadImage(from imgURL: String!) {
let url = URLRequest(url: URL(string: imgURL)!)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil{
print(error)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}
}
Cannot assign value of type String? to type String?.Type.
Change
var userID = String?.self
To
var userID : String?

How can I put cell data into a cell class instead of VC class?, iOS, Swift

I want to move some code from my cell for row into its own cell class to make it a little tidier.
Here is my code.
My array of dictionaries.
var appInfo = [[String:Any]]()
My cell class.
class resultsCell: UITableViewCell {
#IBOutlet weak var iconPicture: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var ratingLabel: UILabel!
func setInfo() {
}
}
My VC cellForRow.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "resultsCell", for: indexPath) as? resultsCell {
let appCell = appInfo[indexPath.row]
let imageUrl = appCell["artwork"] as? String
if imageUrl == nil {
cell.iconPicture.image = #imageLiteral(resourceName: "NoAlbumImage")
}else {
cell.iconPicture.sd_setImage(with: URL(string: "\(imageUrl!)"))
}
cell.titleLabel.text = appCell["name"] as? String
cell.descriptionLabel.text = appCell["desc"] as? String
cell.priceLabel.text = appCell["price"] as? String
let rating = appCell["rating"]
if rating != nil {
cell.ratingLabel.text = "Rating: \((rating!))"
}
return cell
}else {
return UITableViewCell()
}
}
I want to move my cell.label.text's from the VC to the set info function in the cell class.
Here is my JSON decoding and structs.
import Foundation
var appInfo = [[String:Any]]()
class searchFunction {
static let instance = searchFunction()
func getAppData(completion: #escaping (_ finished: Bool) -> ()) {
guard let url = URL(string: BASE_ADDRESS) else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
let appData = try decoder.decode(Root.self, from: data)
appInfo = []
for app in appData.results {
let name = app.trackName
let desc = app.description
guard let rating = app.averageUserRating else { continue }
let price = app.formattedPrice
let artwork = app.artworkUrl60.absoluteString
let appInd = ["name":name, "desc":desc, "rating":rating, "price":price, "artwork":artwork] as [String : Any]
appInfo.append(appInd)
}
completion(true)
}catch let jsonErr {
print("Error seroalizing json", jsonErr)
}
}.resume()
}
}
Structs..
import Foundation
struct Root: Decodable {
var results: [resultsFull]
}
struct resultsFull: Decodable {
var trackName: String
var description: String
var formattedPrice: String
var averageUserRating: Double?
var artworkUrl60: URL
}
First, I would replace that array of dictionaries with an array of structs; that way you don't need all of that downcasting:
struct AppInfo {
var artwork: String?
var title: String?
var description: String?
var price: String?
var rating: String?
}
var appInfo = [AppInfo]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultsCell", for: indexPath) as! ResultsCell
cell.appInfo = self.appInfo[indexPath.row]
return cell
}
Then you can use didSet to update your cell with the values from the struct
class ResultsCell:UITableViewCell {
#IBOutlet weak var iconPicture: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var ratingLabel: UILabel!
var appInfo: AppInfo {
didSet {
iconPicture.image = #imageLiteral(resourceName: "NoAlbumImage")
if let artwork = appInfo.artwork, let artworkURL = URL(string: artwork) {
iconPicture.sd_setImage(with: artworkURL)
}
titleLabel.text = appInfo.title ?? ""
descriptionLabel.text = appInfo.description ?? ""
priceLabel.text = appInfo.price ?? ""
if let rating = appInfo.rating {
ratingLabel.text = "Rating: \(rating)")
} else {
ratingLabel.text = ""
}
}
}
}
Write below function in resultsCell cell.
func setInfo(appCell: [String : Any]) {
let imageUrl = appCell["artwork"] as? String
if imageUrl == nil {
iconPicture.image = #imageLiteral(resourceName: "NoAlbumImage")
}else {
iconPicture.sd_setImage(with: URL(string: "\(imageUrl!)"))
}
titleLabel.text = appCell["name"] as? String
descriptionLabel.text = appCell["desc"] as? String
priceLabel.text = appCell["price"] as? String
let rating = appCell["rating"]
if rating != nil {
ratingLabel.text = "Rating: \((rating!))"
}
}
Now pass your array value to as like below in cellForRowAt method.
let appCell = appInfo[indexPath.row]
cell.setInfo(appCell: appCell)
class ResultsCell: UITableViewCell {
#IBOutlet weak var iconPicture: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var ratingLabel: UILabel!
func setInfo(_ appCell: [String:Any], inIndexPath: IndexPath, _ cntrl: UIViewController) {
let imageUrl = appCell["artwork"] as? String
if imageUrl == nil {
iconPicture.image = #imageLiteral(resourceName: "NoAlbumImage")
}else {
iconPicture.sd_setImage(with: URL(string: "\(imageUrl!)"))
}
titleLabel.text = appCell["name"] as? String
descriptionLabel.text = appCell["desc"] as? String
priceLabel.text = appCell["price"] as? String
let rating = appCell["rating"]
if rating != nil {
ratingLabel.text = "Rating: \((rating!))"
}
}
}
and in your tableView's delegate write :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(
withIdentifier: "your Results Cell ID from storyboard",
for: indexPath) as? resultsCell {
let appCell = appInfo[indexPath.row]
cell.setInfo(appCell, inIndexPath: indexPath, self)
return cell
}else {
return UITableViewCell()
}
}
For further just remove the array of dictionaries and it's better to use structs of models.

Why is this Swift struct instantiation crashing?

I have a Swift struct Reflection like this:
struct Reflection {
let title: String
let body: String
let author: String
let favorite: Bool
let creationDate: Date
let id: UUID
}
extension Reflection {
var plistRepresentation: [String: AnyObject] {
return [
"title": title as AnyObject,
"body": body as AnyObject,
"author": author as AnyObject,
"favorite": favorite as AnyObject,
"creationDate": creationDate as AnyObject,
"id": id as AnyObject
]
}
init(plist: [String: AnyObject]) {
title = plist["title"] as! String
body = plist["body"] as! String
author = plist["author"] as! String
favorite = plist["favorite"] as! Bool
creationDate = plist["creationDate"] as! Date
id = plist["id"] as! UUID
}
}
class StorageController {
fileprivate let documentsDirectoryURL = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask)
.first!
fileprivate var notesFileURL: URL {
return documentsDirectoryURL
.appendingPathComponent("Notes")
.appendingPathExtension("plist")
}
func save(_ notes: [Reflection]) {
let notesPlist = notes.map { $0.plistRepresentation } as NSArray
notesPlist.write(to: notesFileURL, atomically: true)
}
func fetchNotes() -> [Reflection] {
guard let notePlists = NSArray(contentsOf: notesFileURL) as? [[String: AnyObject]] else {
return []
}
return notePlists.map(Reflection.init(plist:))
}
}
class StateController {
fileprivate let storageController: StorageController
fileprivate(set) var notes: [Reflection]
init(storageController: StorageController) {
self.storageController = storageController
self.notes = storageController.fetchNotes()
}
func add(_ note: Reflection) {
notes.append(note)
storageController.save(notes)
}
func update(_ note: Reflection) {
for (index, storedNote) in notes.enumerated() {
guard storedNote.id == note.id else {
continue
}
notes[index] = note
storageController.save(notes)
break
}
}
}
Instantiating a Reflection like this in viewWillAppear crashes my app:
import UIKit
class NotesViewController: UIViewController {
var stateController: StateController!
fileprivate var dataSource: FeedDataSource!
#IBOutlet var tableView: UITableView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let reflection = Reflection(title: "Hello", body: "world", author: "Alex", favorite: true, creationDate: Date(), id: UUID())
//stateController.add(reflection)
dataSource = FeedDataSource(notes: stateController.notes)
tableView.dataSource = dataSource
tableView.reloadData()
}
class FeedDataSource: NSObject {
var notes: [Reflection]!
init(notes: [Reflection]) {
self.notes = notes
}
}
extension FeedDataSource: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return notes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reflectionCell", for: indexPath) as! ReflectionCell
let index = indexPath.row
let note = notes[index]
cell.model = ReflectionCell.Model(data: note)
return cell
}
}
The cell class:
class ReflectionCell: UITableViewCell {
#IBOutlet weak fileprivate var titleLabel: UILabel!
#IBOutlet weak fileprivate var bodyLabel: UILabel!
#IBOutlet weak fileprivate var authorLabel: UILabel!
#IBOutlet weak fileprivate var bookmarkButton: UIButton!
fileprivate var id: UUID!
var model: Model? {
didSet {
guard let model = model else {
return
}
titleLabel.text = model.title
bodyLabel.text = model.body
authorLabel.text = model.author
bookmarkButton.isSelected = model.favorite
id = model.id
}
}
override func awakeFromNib() {
super.awakeFromNib()
bookmarkButton.setImage(#imageLiteral(resourceName: "Bookmark-Highlighted"), for: .selected)
}
}
extension ReflectionCell {
struct Model {
let title: String
let body: String
let author: String
let favorite: Bool
let id: UUID
init(data: Reflection) {
title = data.title
body = data.body
author = data.author
favorite = data.favorite
id = data.id
}
}
}
I get no console output, just a main thread SIGABRT error. What could be going on?
Like an idiot I was cleaning up my code and commented out the line registering the nib for the reuse identifier. However, I do think it would help if Xcode could print out a useful error message for such a mistake.

Retrieve Image From Firebase

extension of Firebase Database Structure
After uploaded the image, name and phone to the Firebase Database and Firebase Storage.
I am having trouble with retrieving the image from the Firebase to the Table View.
This is the Table View Class :
#IBOutlet var tableViewHongKong: UITableView!
var restaurantList = [RestaurantModel]()
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference().child("restaurants")
ref?.observe(FIRDataEventType.value, with: {(snapshot) in
if snapshot.childrenCount>0
{
self.restaurantList.removeAll()
for restaurants in snapshot.children.allObjects as![FIRDataSnapshot]
{
let restaurantObject = restaurants.value as? [String: AnyObject]
let restaurantName = restaurantObject?["name"]
let restaurantPhone = restaurantObject?["phone"]
let restaurant = RestaurantModel(name: name as! String?, phone: phone as! String?)
self.restaurantList.append(restaurant)
}
}
self.tableViewHongKong.reloadData()
})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return restaurantList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewControllerTableViewCell
let restaurant: RestaurantModel
restaurant = restaurantList[indexPath.row]
cell.nameLabel.text = restaurant.name
return cell
}
}
This is the Table View Cell Class :
#IBOutlet var myImage: UIImageView!
#IBOutlet var nameLabel: UILabel!
This is the Restaurant Model Class:
var name: String?
var phone: String?
init(name:String?, phone:String?) {
self.name = name;
self.phone = phone
}
As the image uploaded in another class, Restaurant.
var imageURL = ""
func addRestaurant()
{
ref = FIRDatabase.database().reference().child("restaurants")
let key = ref?.childByAutoId().key
let name = addName.text
let phone = addPhone.text
ref?.child(key!).setValue(["name": name, "phone": phone, "image": imageURL])
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
addImage.image = image
var data = Data()
data = UIImagePNGRepresentation(image!)!
let uniqueName = NSUUID().uuidString
let imageRef = FIRStorage.storage().reference().child("restaurantImage").child("\(uniqueName)")
imageRef.put(data, metadata: nil).observe(.success){(snapshot) in
self.imageURL = (snapshot.metadata?.downloadURL()?.absoluteString)!
}
self.dismiss(animated: true, completion: nil)
}
For more detail, may visit Firebase Database Structure
Thank you very much ! ^.^

Resources