Man, UITableView's just do not want to work with me. I have been outputting strings to Firebase storage and I see the values stored. My problem is that I cannot output any of those strings into the UITableView. I just see a blank table view and when I go and try to see what is being outputted by thoughtObjects.thoughts it just says "nil." If anyone can help figure out what is wrong that would be appreciated. Thank you so much StackOverflow.
import UIKit
import Firebase
import FirebaseDatabase
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var inputThoughtTextField: UITextField!
#IBOutlet weak var successfulUploadLbl: UILabel!
#IBOutlet weak var tableView: UITableView!
var refThoughts: DatabaseReference!
var thoughtList = [ThoughtModel]()
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return thoughtList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
//creating a cell using the custom class
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! VCTableViewCell
//the artist object
let thoughtObjects: ThoughtModel
//getting the artist of selected position
thoughtObjects = thoughtList[indexPath.row]
//adding values to labels
cell.wordCloud.text = thoughtObjects.thoughts
//print(cell.wordCloud.text)
//returning cell
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
refThoughts = Database.database().reference().child("thoughts");
refThoughts.observe(DataEventType.value, with: { (snapshot) in
//if the reference have some values
if snapshot.childrenCount > 0 {
//clearing the list
self.thoughtList.removeAll()
//iterating through all the values
for thoughts in snapshot.children.allObjects as! [DataSnapshot] {
//getting values
let thoughtsObject = thoughts.value as? [String: AnyObject]
let thoughtText = thoughtsObject?["thoughts"]
let thoughtId = thoughtsObject?["id"]
//creating artist object with model and fetched values
let thoughtCreation = ThoughtModel(id: thoughtId as! String?, thoughts: thoughtText as! String?)
//appending it to list
self.thoughtList.append(thoughtCreation)
}
//reloading the tableview
self.tableView.reloadData()
}
})
}
#IBAction func buttonAddThought(_ sender: UIButton){
addThought()
}
func addThought(){
let key = refThoughts.childByAutoId().key
let thought = ["id": key,
"Thoughts": inputThoughtTextField.text! as String
]
refThoughts.child(key).setValue(thought)
successfulUploadLbl.text = "Thought Uploaded"
}
}
Related
I have my value from Firebase but Swift doesn't want to put it in my label.
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
To summarize, my database look like that:
Firebase database
I've created a standard model call ServiceModel:
import Foundation
class ServiceModel {
var name: String?
var category: String?
var pricing: String?
init(name: String?, category: String?, pricing: String?){
self.name = name
self.category = category
self.pricing = pricing
}
}
I want to display this values into a TableView, so I've created a custom cell like this (very standard too):
import UIKit
class SubscriptionTableViewCell: UITableViewCell {
#IBOutlet weak var imageService: UIImageView!
#IBOutlet weak var labelName: UILabel!
#IBOutlet weak var labelCategory: UILabel!
#IBOutlet weak var labelPricing: 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
}
}
And now, here is the controller of my view:
import UIKit
import FirebaseDatabase
class SecondViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
var refServices:DatabaseReference!
#IBOutlet weak var ListSub: UITableView!
var serviceList = [ServiceModel]()
var databaseHandle:DatabaseHandle?
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return serviceList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCell", for: indexPath) as! SubscriptionTableViewCell
let service: ServiceModel
service = serviceList[indexPath.row]
//cell.imageService.image = UIImage(named: service.name! + ".png")
cell.labelName?.text = service.name //ERROR HERE
cell.labelCategory?.text = service.category
cell.labelPricing?.text = service.pricing
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
ListSub.delegate = self
ListSub.dataSource = self
refServices = Database.database().reference().child("Categories");
refServices.observe(DataEventType.value, with: { (snapshot) in
if snapshot.childrenCount > 0 {
self.serviceList.removeAll()
for services in snapshot.children.allObjects as! [DataSnapshot] {
let serviceObject = services.value as? [String: AnyObject]
let serviceName = serviceObject?["Name"]
let serviceCategory = serviceObject?["Category"]
let servicePricing = serviceObject?["Pricing"]
let service = ServiceModel(name: serviceName as! String?, category: serviceCategory as! String?, pricing: servicePricing as! String?)
self.serviceList.append(service)
}
self.ListSub.reloadData()
}
})
}
When I launch this view, I have the error mentioned earlier.
When I debug, I see that I have the right values in service.name, service.category and service.pricing
It seems that I don't correctly handle Optional values, but I cannot see what is wrong.
Thanks for your help.
Potential lines to be crashed in case of optional unwrapping is this line
refServices = Database.database().reference().child("Categories");
refServices.observe(DataEventType.value, with: { (snapshot) in
Try to pur breakpoint and check if refServices is initialised properly or make ti to be optional not using !
Hope this help
Ps. please remove ; out of your Swift code :P
Use this code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCell", for: indexPath) as! SubscriptionTableViewCell
let service = serviceList[indexPath.row]
// If you sure that you have to display all the info use this code
if let name = service.name, let category = service.category, let price = service.pricing {
cell.labelName.text = name
// set other data also here....
}
// If you know any value may be empty or not exists then use this code.
if let name = service.name {
cell.labelName.text = name
}
if let category = service.category {
cell.labelCategory.text = service
}
if let pricing = service.pricing {
cell.labelPricing.text = pricing
}
return cell
}
Did you register your custom UITableViewCell with your tableView? Put this line into the init() function of your ViewController:
ListSub.register(SubscriptionTableViewCell.classForCoder(), forCellReuseIdentifier: "SubCell")
If you debug this function, what did you see for your service
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCell", for: indexPath) as! SubscriptionTableViewCell
let service: ServiceModel
//Put a breakpoint here
service = serviceList[indexPath.row]
//Put a breakpoint here
//cell.imageService.image = UIImage(named: service.name! + ".png")
cell.labelName?.text = service.name
cell.labelCategory?.text = service.category
cell.labelPricing?.text = service.pricing
return cell
}
I plan to retrieval data from Database Firebase to TableView by this code what is wrong with my code and how can i fix it to let all details send to my table view
Firebase database
Run at Phone
And this is my data in the database:
import UIKit
import Firebase
class Ordersv: UIViewController, UITableViewDataSource, UITableViewDelegate {
var array = [String]()
var ref: DatabaseReference!
var handle: DatabaseHandle!
#IBOutlet weak var TableView: UITableView!
#IBAction func add (_ sender: Any){
if textField.text != ""{
ref.child("list").childByAutoId().setValue(textField.text)
textField.text = ""
}
}
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
handle = ref?.ref.child ("Orders/Customer/Detils/").observe(.value, with: { (snapshot) in
if let item = snapshot.value as? String {
self.array.append(item)
self.TableView.reloadData()
}
})
self.TableView.delegate = self
self.TableView.dataSource = self
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = TableView.dequeueReusableCell(withIdentifier: "Cell")! as UITableViewCell
cell.textLabel?.text = array[indexPath.row]
return cell
}
}
There are a few things wrong wit the code:
You never initialize ref.
When you observe .value, you get multiple nodes back. Your code doesn't handle this fact.
To fix both, I recommend:
let ref = Database.database().reference()
handle = ref.child("Orders/Customer/Detils/").observe(.childAdded, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let name = value?["Name"] as? String ?? ""
self.array.append(name)
self.TableView.reloadData()
})
The above code observes the .childAdded event, which fires immediately for each existing child node, and then once for every subsequent child that is added.
I am making an iOS app but I keep getting this error:
'NSInternalInconsistencyException', reason: 'attempt to insert row 0 into section 0, but there are only 0 sections after the update'
I have researched this question for 2 days now but I don't know what's wrong. I am putting my code down below.
import UIKit
import FirebaseDatabase
import FirebaseAuth
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var databaseRef = Database.database().reference()
var loggedInUser:AnyObject?
var loggedInUserData:NSDictionary?
#IBOutlet weak var aivLoading: UIActivityIndicatorView!
#IBOutlet weak var homeTableView: UITableView!
var posts = [NSDictionary]()
override func viewDidLoad() {
super.viewDidLoad()
self.loggedInUser = Auth.auth().currentUser
self.databaseRef.child("users").child(self.loggedInUser!.uid).observeSingleEvent(of: .value) { (snapshot: DataSnapshot) in
self.loggedInUserData = snapshot.value as? NSDictionary
self.databaseRef.child("posts").child(self.loggedInUser!.uid).observe(.childAdded, with: { (snapshot: DataSnapshot) in
self.posts.insert(snapshot.value as! NSDictionary, at: 0)
self.homeTableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic)
self.aivLoading.stopAnimating()
}){(error) in
ProgressHUD.showError("There was an error, try again")
}
}
self.homeTableView.rowHeight = UITableViewAutomaticDimension
self.homeTableView.estimatedRowHeight = 140
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: HomeTableViewCell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
let post = posts[(self.posts.count-1) - (indexPath.row)]["text"] as! String
cell.configure("Anonymous", post: post)
return cell
}
}
In my code, it refers to a dequeueReusableCell, with the identifier HomeTableViewCell, which is a Swift file. Here is the code for that Swift file:
import UIKit
import FirebaseDatabase
import Firebase
import FirebaseAuth
class HomeTableViewCell: UITableViewCell {
#IBOutlet weak var nameConstant: UILabel!
#IBOutlet weak var post: UITextView!
override open func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
open func configure(_ nameConstant: String, post: String) {
self.post.text = post
self.nameConstant.text = "Anonymous"
}
}
I know there are similar questions to mine but a lot of those are in Objective-C. I've looked at the Swift ones too but they don't help.
If anyone has any ideas to fix this that would be great. Thanks in advance!
In your code you're always returning 1 for number of rows. But i guess you should be returning posts.count right? Every time you insertRows(at:... the table checks consistency through the delegate. There's also something weird, you're appending to your list (self.posts.append(snapshot.value as! NSDictionary)) but then you're inserting row 0-0?, I'll assume you want to insert new post to the top. Moreover if you have just one section, you don't need to implement the method.
So here's the code (I'm assuming the firebase and cell configuration code is correct):
import UIKit
import FirebaseDatabase
import FirebaseAuth
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var databaseRef = Database.database().reference()
var loggedInUser:AnyObject?
var loggedInUserData:NSDictionary?
#IBOutlet weak var aivLoading: UIActivityIndicatorView!
#IBOutlet weak var homeTableView: UITableView!
var posts = [NSDictionary]()
override func viewDidLoad() {
super.viewDidLoad()
self.loggedInUser = Auth.auth().currentUser
self.databaseRef.child("users").child(self.loggedInUser!.uid).observeSingleEvent(of: .value) { (snapshot: DataSnapshot) in
self.loggedInUserData = snapshot.value as? NSDictionary
self.databaseRef.child("posts").child(self.loggedInUser!.uid).observe(.childAdded, with: { (snapshot: DataSnapshot) in
self.posts.insert(snapshot.value as! NSDictionary, at: 0)
self.homeTableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic)
self.aivLoading.stopAnimating()
}){(error) in
ProgressHUD.showError("There was an error, try again")
}
}
self.homeTableView.rowHeight = UITableViewAutomaticDimension
self.homeTableView.estimatedRowHeight = 140
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: HomeTableViewCell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
let post = posts[(self.posts.count-1) - (indexPath.row)]["text"] as! String
cell.configure("Anonymous", post: post)
return cell
}
}
I hope it fixes your problem ;)
I have a folder in my Database called "Cars", within the folder is a list of car brands, I want to retrieve all the brands and put it in a UITableView. Then when you press on a brand it will show the models of the brand. I have a trouble retrieving the list of cars at the moment. This is the screenshot of my Database and my code for the view controller.
import UIKit
import Firebase
import FirebaseDatabase
import SDWebImage
struct carStruct {
let cars : String!
}
class CarMakeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var cars = [carStruct]()
override func viewDidLoad() {
super.viewDidLoad()
let ref = Database.database().reference().child("Cars")
ref.observeSingleEvent(of: .value, with: { snapshot in
print(snapshot.childrenCount)
for rest in snapshot.children.allObjects as! [DataSnapshot] {
guard let value = rest.value as? Dictionary<String,Any> else { continue }
guard let make = value["Cars"] as? String else { continue }
let cars = carStruct(cars: make)
self.cars.append(cars)
}
self.cars = self.cars.reversed(); self.tableView.reloadData()
})
}
#IBOutlet weak var tableView: UITableView!
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cars.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellMake")
let label1 = cell?.viewWithTag(21) as! UILabel
label1.text = cars[indexPath.row].cars
return cell!
}
}
I think you should make another struct for holding data that is inside of the model of the car (so, for this struct you should dig little bit deeper). As for retrieving data now, I suggest you to read this article, which helped me a lot not long ago.
I am successfully downloading and printing data from Realm database. Here is my log:
Item(id: Optional(0), name: Optional("Item (0)"), descr: Optional("Description of item (0)"),
icon: Optional("http://192.168.1.101:8080/api/items/0/icon.png"),
url: Optional("http://192.168.1.101:8080/api/items/0")))
Now I have to assign those values on actual list and I am getting a clean sheet tableview. How to do it properly? I am using .xib as tablewViewCell. I am thankful for any tips.
class ItemRealm : Object {
dynamic var id = 0
dynamic var name = ""
dynamic var desc = ""
dynamic var icon = ""
override class func primaryKey() -> String? {
return "id"
}
}
class ViewController: UIViewController, UITableViewDataSource, UISearchBarDelegate {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
let realm = try! Realm()
let results = try! Realm().objects(ItemRealm.self).sorted(byKeyPath: "id")
let SERVER_URL = "http://192.168.1.101:8080/api/items"
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(SERVER_URL).responseJSON { response in
let items = [Item].from(jsonArray: response.result.value as! [Gloss.JSON])
print(items?[0] as Any)
try! self.realm.write {
for item in items! {
let itemRealm = ItemRealm()
itemRealm.id = item.id!
itemRealm.name = item.name!
itemRealm.desc = item.descr!
itemRealm.icon = item.icon!
self.realm.add(itemRealm)
}
}
_ = self.realm.objects(ItemRealm.self)
// print(items?[0] as Any)
}
// Do any additional setup after loading the view.
tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell")
}
// MARK: - UITableView data source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return results.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell
var object: ItemRealm
object = self.results[indexPath.row] as ItemRealm
cell.item = object
return cell
}
}
I think you are missing self.tableView.reloadData() after getting data from the response. Consider also assigning fetched data to your results variable.