This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 4 years ago.
So I've gone through every possible solution offered on SO and tried all the solutions but my case seems to be singular. I have a tableview in a 'HomeViewController' which is connected to the HomeViewController.swift file and there's also a HomeViewControllerTableViewCell.swift file. Here's my code:
HomeViewController.swift:
import Firebase
import FirebaseDatabase
import UIKit
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return artistlists.count
}
var artistlists = [ArtistList]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "celler", for: indexPath) as! HomeViewControllerTableViewCell
let artists : ArtistList
artists=artistlists[indexPath.row]
print("Here")
cell.labelName.text = artists.name
cell.labelCity.text = artists.city
cell.labelDate.text = artists.date
return cell
}
#IBOutlet weak var tableArtists: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
var ref: DatabaseReference!
ref = Database.database().reference()
ref.child("Fund").observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.childrenCount)
if snapshot.childrenCount > 0 {
self.artistlists.removeAll()
for artist in snapshot.children.allObjects as! [DataSnapshot] {
//temporary test code
if let artistDict = artist.value as? [String: Any] {
if let aName = artistDict["artist_name"] as? String {
print("first name was \(aName)")
} else {
print("ARTIST NAME WAS NIL! RUN FOR YOUR LIVES!")
}
} else {
print("artist.value was nil!")
}
//end of temporary test code
// let artistObject = artist.value as? [String: AnyObject]
// let artistName = artistObject?["artist_name"]
// let artistCity = artistObject?["perf_location"]
// let artistDate = artistObject?["target_date"]
// let artistName2:String = String(format: "%#", artistName as! CVarArg)
// print(artistName2)
// let artistCity2:String = String(format: "%#", artistCity as! CVarArg)
// let artistDate2:String = String(format: "%#", artistDate as! CVarArg)
// let artisty = ArtistList(name: artistName2 as String?, city: artistCity2 as String?, date: artistDate2 as String?)
// self.artistlists.append(artisty)
}
self.tableArtists.reloadData()
}
// Do any additional setup after loading the view.
})
{ (error) in
print(error.localizedDescription)
}
self.tableArtists.register(HomeViewControllerTableViewCell.self, forCellReuseIdentifier: "celler")
}
HomeViewControllerTableViewCell.swift
import UIKit
import FirebaseDatabase
import Firebase
class HomeViewControllerTableViewCell: UITableViewCell {
#IBOutlet weak var labelName: UILabel!
#IBOutlet weak var labelCity: UILabel!
#IBOutlet weak var labelDate: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
ArtistList.swift:
import Foundation
class ArtistList
{
var name: String?
var city: String?
var date: String?
init(name: String?, city: String?, date: String?) {
self.city = city
self.date = date
self.name = name
}
}
I'm getting an error in HomeViewController.swift, line 28-30, saying 'Unexpectedly found nil while wrapping an optional value'.
cell.labelName.text = artists.name,
cell.labelCity.text = artists.city,
cell.labelDate.text = artists.date
are lines 28-30.
Can someone please help me out with this?
Broken outlet links are a very common cause of such errors. My guess is either the outlet links to labelName, labelCity, and labelDate are not connected in your HomeViewControllerTableViewCell, or your cell with the identifier "celler" is not set up as a as a cell of type HomeViewControllerTableViewCell.
Related
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.
When i run the code and click the segue to description view controller appear error in Debugging .Could not cast value of type '__NSCFString' (0x10354a248) to 'UIImage' (0x104c42b48).
in main view controller error got this Thread 1: signal SIGABRT
MainViewController.swift
import UIKit
import Alamofire
import AlamofireImage
import SDWebImage
class MainViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView?
var foods: [[String: Any]] = [[String: Any]]()
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request("https://api.myjson.com/bins/1bnsyj").responseJSON { (response) in
if let responseValue = response.result.value as! [String: Any]? {
print(responseValue)
if let responseFoods = responseValue["items"] as! [[String: Any]]? {
self.foods = responseFoods
self.tableView?.reloadData()
}
}
else {
print("error : \(String(describing: response.result.error))")
}
}
// Do any additional setup after loading the view.
}
// MARK: - UITableViewDataSource & UITableViewDelegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return foods.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FoodTableViewCell") as! FoodTableViewCell
if foods.count > 0 {
let eachFood = foods[indexPath.row]
cell.lblFoodName?.text = (eachFood["name"] as? String) ?? ""
cell.lblDescription?.text = (eachFood["description"] as? String) ?? ""
let url = NSURL(string: self.foods[indexPath.row]["photoUrl"]! as! String)
cell.imageViewFood?.af_setImage(withURL: url! as URL, placeholderImage: nil, filter: nil,runImageTransitionIfCached: true, completion: nil)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "DetailsViewController") as! DetailsViewController
vc.foodnameseg = foods[indexPath.row]["name"] as! String
vc.descriptionsegue = foods[indexPath.row]["description"] as! String
vc.imagefoodsegue = foods[indexPath.row]["photoUrl"] as! UIImage
self.navigationController?.pushViewController(vc, animated: true)
}
}
DetailsViewController.swift
import UIKit
class DetailsViewController: UIViewController {
var foodnameseg : String = ""
var descriptionsegue : String = ""
var imagefoodsegue = UIImage()
#IBOutlet weak var imagefood: UIImageView!
#IBOutlet weak var lblNameSegue: UILabel!
#IBOutlet weak var descriptionSegue: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
lblNameSegue.text = foodnameseg
descriptionSegue.text = descriptionsegue
imagefood.image = imagefoodsegue
}
}
This line is the culprit:
vc.imagefoodsegue = foods[indexPath.row]["photoUrl"] as! UIImage
You are trying to cast the String as an UIImage.
One solution to this is to add another key to foods[indexPath.row] called "photos" and make sure that it is a UIImage when you're assigning it.
Or you could make a food struct like so:
struct Food
{
var name: String
var photoURL: URL
var photo: UIImage?
}
Replace your foods array's type to [Food]. This should provide more safety in the code and you won't have to force-cast everytime you want to get a photo.
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
}
}
I'm using firebase to make an iOS app. I want to retrieve all the users on my database and display their name and profile picture in a table view. Here is my code for my TableViewCell:
import UIKit
import FirebaseDatabase
import FirebaseAuth
import SDWebImage
class HomeTableViewCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var likeImageView: UIImageView!
#IBOutlet weak var messageImageView: UIImageView!
#IBOutlet weak var likeCountButton: UIButton!
var homeVC: HomeViewController?
var postReference: DatabaseReference!
var post: UserFile?{
didSet {
updateView()
}
}
var user: UserFile? {
didSet {
updateUserInfo()
}
}
override func awakeFromNib() {
super.awakeFromNib()
nameLabel.text = ""
let berryTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleLikeTap))
likeImageView.addGestureRecognizer(berryTapGesture)
likeImageView.isUserInteractionEnabled = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func updateView() {
if let photoURL = post?.picURL {
profileImageView.sd_setImage(with: URL(string: photoURL))
}
API.Post.REF_POSTS.child(post!.id!).observeSingleEvent(of: .value, with: { postSnapshot in
if let postDictionary = postSnapshot.value as? [String:Any] {
let post = UserFile.transformPost(postDictionary: postDictionary, key: postSnapshot.key)
self.updateLike(post: post)
}
})
API.Post.REF_POSTS.child(post!.id!).observe(.childChanged, with: { snapshot in
if let value = snapshot.value as? Int {
self.likeCountButton.setTitle("\(value) berries", for: .normal)
}
})
}
func updateLike(post: UserFile) {
let imageName = post.berries == nil || !post.isBerried! ? "berry" : "berrySelected"
likeImageView.image = UIImage(named: imageName)
// display a message for berries
guard let count = post.berryCount else {
return
}
if count != 0 {
likeCountButton.setTitle("\(count) berries", for: .normal)
} else if post.berryCount == 0 {
likeCountButton.setTitle("Be the first to Like this", for: .normal)
}
}
func incrementberries(forReference ref: DatabaseReference) {
ref.runTransactionBlock({ (currentData: MutableData) -> TransactionResult in
if var post = currentData.value as? [String : AnyObject], let uid = Auth.auth().currentUser?.uid {
var berries: Dictionary<String, Bool>
berries = post["berries"] as? [String : Bool] ?? [:]
var likeCount = post["berryCount"] as? Int ?? 0
if let _ = berries[uid] {
// Unlike the post and remove self from stars
likeCount -= 1
berries.removeValue(forKey: uid)
} else {
// Like the post and add self to stars
likeCount += 1
berries[uid] = true
}
post["berryCount"] = likeCount as AnyObject?
post["berries"] = berries as AnyObject?
currentData.value = post
return TransactionResult.success(withValue: currentData)
}
return TransactionResult.success(withValue: currentData)
}) { (error, committed, snapshot) in
if let error = error {
print(error.localizedDescription)
}
if let postDictionary = snapshot?.value as? [String:Any] {
let post = UserFile.transformPost(postDictionary: postDictionary, key: snapshot!.key)
self.updateLike(post: post)
}
}
}
func handleLikeTap() {
postReference = API.Post.REF_POSTS.child(post!.id!)
incrementberries(forReference: postReference)
}
override func prepareForReuse() {
super.prepareForReuse()
profileImageView.image = UIImage(named: "industribune-default-no-profile-pic")
}
func updateUserInfo() {
nameLabel.text = user?.username
if let photoURL = user?.profileImageURL {
profileImageView.sd_setImage(with: URL(string: photoURL), placeholderImage: UIImage(named: "industribune-default-no-profile-pic"))
}
}
}
I am displaying this cell on my HomeViewController:
import UIKit
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage
import Firebase
class HomeViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
var posts = [UserFile]()
var users = [UserFile]()
override func viewDidLoad() {
super.viewDidLoad()
// for performance set an estimated row height
tableView.estimatedRowHeight = 1
// but also request to dynamically adjust to content using AutoLayout
tableView.rowHeight = UITableViewAutomaticDimension
//tableView.delegate = self
tableView.dataSource = self
loadPosts()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadPosts() {
activityIndicatorView.startAnimating()
API.User.observePosts { (newPost) in
guard let userID = newPost.uid else { return }
self.fetchUser(uid: userID, completed: {
// append the new Post and Reload after the user
// has been cached
self.posts.append(newPost)
self.activityIndicatorView.stopAnimating()
self.tableView.reloadData()
})
}
}
func fetchUser(uid: String, completed: #escaping () -> Void) {
API.User.observeUser(withID: uid) { user in
self.users.append(user)
completed()
}
}
}
extension HomeViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
cell.post = posts[indexPath.row]
cell.user = users[indexPath.row]
cell.homeVC = self
return cell
}
}
I have a lot of craziness going on in my project so let me know if you have any questions and what I'm doing wrong. If it's too complicated to understand I'm ready to erase everything and start over too.
And I do honestly think that I followed all the guidelines to ask a question so don't like shut this question down or something.
That's a lot of code. Try this super reduced example. For this, the users node only stores the name as a child node but it could also have an image, email, address, etc.
Example users node
users
uid_0:
name: "Bert"
uid_1:
name: "Ernie"
and some code
var usersArray = [ [String: Any] ]() //an array of dictionaries.
class ViewController: UIViewController {
//set up firebase references here
override func viewDidLoad() {
super.viewDidLoad()
let usersRef = self.ref.child("users")
usersRef.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let userDict = snap.value as! [String: Any]
self.usersArray.append(userDict)
}
self.tableView.reloadData()
})
and the tableView delegate methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.usersArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
let userDict = self.usersArray[indexPath.row]
cell.text = userDict["name"] as! String
//cell.imge = userDict["image"] etc etc
return cell
}
Now... that all being said. This is the perfect use for an array of UserClass objects instead of the dictionaries.
Here's a starting point....
class UserClass {
var name = ""
var image = ""
func init(snap: DataSnapshot) {
//populate the vars from the snapshot
}
}
var userClassArray = [UserClass]()
Don't copy and paste this as there are probably typos but it should point you in the right direction.
I am getting error in ToDoViewController.Swift here is the overall code:
I am makeing a simple app for taking orders from customers. and orders will store in Firebase.
View Controller.Swift
import UIKit
import Firebase
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var todoList = [Todo]()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadData()
}
func loadData() {
self.todoList.removeAll()
let ref = FIRDatabase.database().reference()
ref.child("todoList").observeSingleEvent(of: .value, with: { (snapshot) in
if let todoDict = snapshot.value as? [String:AnyObject] {
for (_,todoElement) in todoDict {
print(todoElement);
let todo = Todo()
todo.name = todoElement["name"] as? String
todo.message = todoElement["message"] as? String
todo.reminderDate = todoElement["date"] as? String
self.todoList.append(todo)
}
}
self.tableView.reloadData()
}) { (error) in
print(error.localizedDescription)
}
}
//MARK: TableView datasource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.todoList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoCell")
cell!.textLabel?.text = todoList[indexPath.row].name
return cell!
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
ToDoViewController
import UIKit
import Firebase
class ToDoViewController: UIViewController {
var todo:Todo?
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var messageField: UITextField!
#IBOutlet weak var dateFormatter: UIDatePicker!
#IBAction func Done(_ sender: Any) {
if todo == nil {
todo = Todo()
}
// first section
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy hh:mm"
todo?.name = self.nameField.text
todo?.message = self.messageField.text
todo?.reminderDate = dateFormatter.string(from: self.dateFormatter.date)
//second section
let ref = FIRDatabase.database().reference()
let key = ref.child("todoList").childByAutoId().key
let dictionaryTodo = [ "name" : todo!.name! ,
"message" : todo!.message!,
"date" : todo!.reminderDate!]
let childUpdates = ["/todoList/\(key)": dictionaryTodo]
ref.updateChildValues(childUpdates, withCompletionBlock: { (error, ref) -> Void in
self.navigationController?.popViewController(animated: true)
})
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let todoVC = self.storyboard!.instantiateViewController(withIdentifier: "ToDoVC") as! ToDoViewController
todoVC.todo = todoList[indexPath.row]
self.navigationController?.pushViewController(todoVC, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if self.todo != nil {
nameField.text = self.todo?.name
messageField.text = self.todo?.message
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy hh:mm"
let date = dateFormatter.date(from: self.todo!.reminderDate!)
datePicker.date = date!
}
}
}
Todo.Swift
import UIKit
class Todo: NSObject {
var name :String?
var message: String?
var reminderDate: String?
// id which is set from firebase to uniquely identify it
var uniqueId:String?
}
Something is wrong with your code:
Use of un-resolved identifier 'todoList':
todoList is declared in View Controller.Swift and you cannot use it in ToDoViewController.
Cannot assign to property: 'date' is a method:
In the code datePicker is undefined and #IBOutlet weak var dateFormatter: UIDatePicker! should be:
#IBOutlet weak var datePicker: UIDatePicker!
AND In the image dateFormatter.date = date! should be:
datePicker.date = date!