Populating TableView with retrieved data from Firebase with Swift 3 - ios

I've tried to retrieve data and set it into a tableview; I haven't really succeeded on this.
I want to fetch image and text into the tableView from firebase;
import UIKit
import Firebase
class HomePageViewController: UIViewController, UITableViewDelegate {
#IBOutlet weak var homePageTableView: UITableView!
var ref: DatabaseReference!
var imageFiles = [Data]()
var price = [String]()
var refHandle:UInt!
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
fetchUsers()
func fetchUsers() {
refHandle = ref.child("Users").observe(.childAdded, with: { (<#DataSnapshot#>) in
if let retrivedData = DataSnapshot.value(String : AnyObject) {
???
}
})
I'm aware of this is unfinished but I have no clue of how to continue from this point. How do I set it to the table??? and how Do I retrieve the data correctly.
Can't find any documentation about this with the newest update firebase SDK and swift 3.0

The best practice is to feed the retrieved data into model objects and supply to the table view.
This is how modal objects looks like:
class Person {
var firstname: String
var lastname: String
init(firstname: String, lastname: String) {
self.firstname = firstname
self.lastname = lastname
}
}
Now you have to feed the JSON data you got from firebase to this model objects. Once your model object is ready, you have to load the tableview. Tableview has data source methods. Use them to show how to populate data in tableview.
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return modelObjectsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell")!
let modelObject = self.modelObjectsArray[indexPath.row] as! Person
cell.textLabel?.text = modelObject.firstname
return cell
}

Related

How to get the child from a parent in a parent child relationship for realm in swift

What i am trying to do is access a child when I have the parent in realm. In this example I have a simple table view that I want to populate with the child when accessing the parent. The part I am struggling with is trying to find the child when accessing the parent.
This is the viewController that i am trying to access the children:
import UIKit
import Realm
import RealmSwift
class OtherViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var otherTableView: UITableView!
var realm: Realm!
var realmedData = ""
var realmList: Results<Realmed> {
get {
return realm.objects(Realmed.self)
}
}
var realmTwoList: Results<RealmTwo> {
get {
return realm.objects(RealmTwo.self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
realm = try! Realm()
self.otherTableView.delegate = self
self.otherTableView.dataSource = self
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var counted = realm.objects(RealmTwo.self).filter("realmLbl == %#", realmedData)
return counted.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
cell.otherLbl.text = "\(items.spanish)"
}
}
return cell
}
}
this is another method I tried for the cell for row at:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
cell.otherLbl.text = "\(items.spanish)"
}
}
return cell
}
this is the parent realm class:
import Foundation
import Realm
import RealmSwift
class Realmed: Object {
#objc dynamic var label = ""
#objc dynamic var romanNum = ""
#objc dynamic var txt = ""
let realmTwo = List<RealmTwo>()
override static func primaryKey() -> String {
return "label"
}
convenience init(label: String, romanNum: String, txt: String) {
self.init()
self.label = label
self.romanNum = romanNum
self.txt = txt
}
}
and this is the realm class for the child:
import Foundation
import UIKit
import Realm
import RealmSwift
class RealmTwo: Object {
#objc dynamic var realmLbl = String()
#objc dynamic var spanish = String()
#objc dynamic var french = String()
let realmed = LinkingObjects(fromType: Realmed.self, property: "realmTwo")
convenience init(realmLbl: String, spanish: String, french: String) {
self.init()
self.realmLbl = realmLbl
self.spanish = spanish
self.french = french
}
}
When I run this as is, the only thing that populates the tableview is the last value saved to realm.
In this example the children are the strings: "Uno" and "Un", and I want them both to populate the tableView, but the tableView is only populated by the last value in realm, in this case, "Un".
Through research I found out that it is because I am looping through the realm value to get the child. The problem with that is that the only way to get to the child is with the loop but then it can't populate a tableView. It seems like a lose-lose situation.
What I am curious about is how to access the child when you have a parent in realm so that I am able to populate a tableView.
If you need anything please ask. Thank you
i think I got something. I figured that what I needed was an array, and it seems that it is unwise to change List to an Array, so what i did was get the content from the List and put it in an array, since it is easier to put data in a tableview from an array.
This is the array that i created:
var realmArr = [String]()
and this is the cell for row at for the tableView:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
self.realmArr.append(items.spanish)
}
}
cell.otherLbl.text = "\(realmArr[indexPath.row])"
return cell
}
I am not sure if this is okay, but it is the only thing that I can think of.
Thank you for all the help.
Let me address this at a high level with a few code snippets. The question is using Objects so let's take a more concrete example of Person and Dog. In this example we have a list of Person Objects each one owning one dog. So we have a single direction relationship
First we have a Person and Dog class
class DogClass: Object {
#objc dynamic var name: String = ""
}
class PersonClass: Object {
#objc dynamic var name: String = ""
#objc dynamic var dog: DogClass?
}
Here's a viewController class that contains a tableView of people
class peopleVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
var peopleResults: Results<PersonClass>!
override func viewDidLoad() {
super.viewDidLoad()
let realm = RealmService //or however you talk to your realm
self.tableView.delegate = self
self.tableView.dataSource = self
self.peopleResults = realm.objects(PersonClass.self) //loads Person objects
self.tableView.reloadData() //shows the list
}
and within that class, the tableView delegate methods that populate our tableview and handle a tap on a row
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return peopleResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: textCellIdentifier, for: indexPath as IndexPath)
let row = indexPath.row
let person = self.peopleResults[row]
cell.textLabel?.text = person.name
return cell
}
//when a row is tapped we need to determine the row, which will be included
// in the indexPath property with indexPath.row
// From there get the object from the dataSource array via it's row index
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let row = indexPath.row
let person = self.peopleResults[row]
let dog = person.dog
//at this point you have the dog object and you could print the name
print(dog.name)
//or pass it to a detail view via a segue etc
}

Data Parsing firebase

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.

FireBase is returning strings as nil

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

How to retrieve a list in Firebase database folder?

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.

ObjectMapper displayed model in TableView Swift

I am new to Swift , i parsing my JSON by using ObjectMapper but I want data displayed in TableView
I do not know how to do that
My Model:
import Foundation
import ObjectMapper
import SwiftyJSON
class AllCnannelModel : Mappable {
var id : Int?
var name: String?
var url : URL?
var picture : URL?
var category_id: Int?
required init?(map: Map) {}
func mapping(map: Map) {
id<-map["id"]
name<-map["name"]
url<-map["url"]
picture<-map["picture"]
category_id<-map["category_id"]
}
}
My TableView :
var name = [String]()
var urlChannel = [URL]()
override func viewDidLoad() {
super.viewDidLoad()
let URL = "http://52.50.138.211:8080/ChanelAPI/chanels"
Alamofire.request(URL).responseArray { (response: DataResponse<[AllCnannelModel]>) in
let channnellArray = response.result.value
if let channnellArray = channnellArray {
for channel in channnellArray {
self.name.append(channel.name!)
}
}
self.tableView.reloadData()
}
}
I can describe one type of data in the array and display:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.name.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = self.name[indexPath.row]
return cell
}
but i want all type of data in one array and display TableViewController
How can you implement?
Did you implemented numberOfSections(in tableView: UITableView) -> Int ?

Resources