Display all data from child node on a tableViewCell - ios

I'm having trouble displaying all of the followers of user on a table view cell with their profile picture and full name (similar to instagram).
A snippet of my firebase JSON structure is:
"followers" : {
"FoFQDAGGX9hntBiBdXYCBHd8yas2" : {
"CjeP35ceAQZJuUPhm7U1eF3Yq4F3" : true,
"FjS4wUpXAUa5aWwXkjvujHxE4He2" : true,
"Gmg1ojNoBiedFPRNSL4sBZz2gSx2" : true,
"PqMkClaPM3W8k7ZSgzAHb3yne5D3" : true,
"buS4recuDpdg60ckFqwjoU344TC2" : true
},
"users" : {
"CjeP35ceAQZJuUPhm7U1eF3Yq4F3" : {
"email" : "bbbb#gmail.com",
"fullname" : "Bbbb",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/pinion-4896b.appspot.com/o/profile_image%2FCjeP35ceAQZJuUPhm7U1eF3Yq4F3?alt=media&token=0449c633-b397-4452-b2df-41f3a5390084",
"work" : "Nottingham",
},
Code in the table view cell (FollowersTableViewCell):
#IBOutlet weak var followersProfileImage: UIImageView!
#IBOutlet weak var followersNameLabel: UILabel!
var user: UserModel? {
didSet {
updateView()
}
}
func updateView() {
followersNameLabel.text = user?.fullname
if let photoUrlString = user?.profileImageUrl {
let photoUrl = URL(string: photoUrlString)
followersProfileImage.sd_setImage(with: photoUrl, placeholderImage: UIImage(named: "placeholderImg"))
}
}
EDIT:
Code in view controller (FollowersViewController)
#IBOutlet weak var tableView: UITableView!
var users: [UserModel] = []
func loadusers() {
let ref = Database.database().reference()
guard let currentUser = Auth.auth().currentUser?.uid else { return }
var followersNames = [String]()
var profileImage = [String]()
let followersRef = ref.child("followers").child(currentUser) //retreives all nodes in the following node
followersRef.observe(DataEventType.value, with: { snapshot in
print(snapshot.children.allObjects)
for child in snapshot.children { //build the array of keys
let snap = child as! DataSnapshot
let key = snap.key
let userRef = ref.child("users").child(key) //get the user name and profile image from the users node
userRef.observeSingleEvent(of: .value, with: { snapshot in
let followersName = snapshot.childSnapshot(forPath: "fullname").value as! String
let followersProfileImageUrl = snapshot.childSnapshot(forPath: "profileImageUrl").value as! String
print(followersName)
print(followersProfileImageUrl)
followersNames.append(followersName)
profileImage.append(followersProfileImageUrl)
self.tableView.reloadData()
})
}
})
}
extension FollowersViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FollowersTableViewCell", for: indexPath) as! FollowersTableViewCell
let user = users[indexPath.row]
cell.user = user
return cell
}
}
Now the code runs and the profile picture and fullname of the followers are printed on the console but doesn't show anything on the table view of the app - thanks in advance :)
Update:
User model definition
class UserModel {
var email: String?
var work: String?
var profileImageUrl: String?
var fullname: String?
var id: String?
}
extension UserModel {
static func transformUser(dict: [String: Any], key: String) -> UserModel {
let user = UserModel()
user.email = dict["email"] as? String
user.work = dict["work"] as? String
user.profileImageUrl = dict["profileImageUrl"] as? String
user.fullname = dict["fullname"] as? String
user.id = key
return user
}
}

Your TableView does not display any data because you don't populate users array at any point.
I might want to instantiate an UserModel object in observeSingleEvent implementation, add the object to users array and invoke reloadData (or insertRows) method also right after that. (Instead of outside the implementation block)
As requested, here is a quick (and dirty) way to create an user object and refresh the UI
let user = UserModel()
user.fullname = snapshot.childSnapshot(forPath: "fullname").value as? String
user.profileImageUrl = snapshot.childSnapshot(forPath: "profileImageUrl").value as? String
self.users.append(user)
self.tableView.reloadData()

Related

Swift display firebase data on tableview not shown

im making application with firebase as a database, and i seems cant to show my data to my tableview. i check on my firebase all my data is good even when i add new data the data is immediately shown in my firebase. but seems like thers some miss logic i have here....can someone help me?
*Edit theres 1 line where the code wont work
this is my main controller:
class MainController: UITableViewController, AddPatientControllerr {
private var patientLists = [PatientList]()
var Segue : String = "PatientName"
var Segue2 : String = "PatientNotes"
let user : User = Auth.auth().currentUser!
private var rootRef : DatabaseReference!// 1. buat nyambung ke root db
override func viewDidLoad() {
super.viewDidLoad()
self.rootRef = Database.database().reference()
populateList()
tableView.delegate = self
tableView.dataSource = self
}
// MARK : Firebase Function
private func populateList() {
self.rootRef.child(self.user.emailWithoutSpecialChar).observe(.value) { (snapshot) in
self.patientLists.removeAll()
let pasienListDict = snapshot.value as? [String:Any] ?? [:]
for (key,_) in pasienListDict {
if let pasienlistdict = pasienListDict[key] as? [String:Any]{
if let pasienlist = PatientList(pasienlistdict) { // this line of code is not working
self.patientLists.append(pasienlist)
}else {
print("your condition not working")
}
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
// MARK : Func delegate
func addPatientData(controller: UIViewController, nama: String, tglLahir: String, Telp: String, berat: String, Tinggi: String, golDarah: String) {
let patientList = PatientList(name: nama, tglLahir: tglLahir, Telp: Telp, berat: berat, Tinggi: Tinggi, golDarah: golDarah)
self.patientLists.append(patientList)
let userRef = self.rootRef.child(self.user.emailWithoutSpecialChar)
let patientListRef = userRef.child(patientList.name)
patientListRef.setValue(patientList.toDictionary())
controller.dismiss(animated: true, completion: nil)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
// MARK : Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == Segue {
let nc = segue.destination as! UINavigationController
let addPatientName = nc.viewControllers.first as! ProfileController
addPatientName.delegate = self
}
else if segue.identifier == Segue2 {
guard let indexPath = self.tableView.indexPathForSelectedRow else {return}
let nc = segue.destination as! PasienProfileController
nc.pasien = self.patientLists[indexPath.row]
}
}
//MARK : TableView
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let pasienList = self.patientLists[indexPath.row]
let pasienListRef = self.rootRef.child(pasienList.name)
pasienListRef.removeValue()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.patientLists.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? MainCell else {return UITableViewCell()}
let patientListt = self.patientLists[indexPath.row]
cell.NameLbl.text = patientListt.name
return cell
}
}
and this is the model where i keep the data and dictionary :
import Foundation
typealias JSONDictionary = [String:Any]
class PatientList {
var name : String!
var tglLahir : String!
var Telp : String!
var berat : String!
var Tinggi : String!
var golDarah : String!
var patientNote :[PatientNote] = [PatientNote]() //ini buat nyimpen notes2 dari tiap2 pasien
init(name : String, tglLahir : String, Telp : String, berat : String, Tinggi : String, golDarah : String) {
self.name = name
self.tglLahir = tglLahir
self.berat = berat
self.Tinggi = Tinggi
self.golDarah = golDarah
self.Telp = Telp
}
init?(_ dictionary :[String:Any]){
guard let name = dictionary["Name"] as? String else {
return nil
}
guard let berat = dictionary["BeratBadan"] as? String else {
return nil
}
guard let tglLahir = dictionary["TanggalLahir"] as? String else {
return nil
}
guard let Tinggi = dictionary["TinggiBadan"] as? String else {
return nil
}
guard let golDarah = dictionary["GolonganDarah"] as? String else {
return nil
}
guard let Telp = dictionary["Telefon"] as? String else {
return nil
}
self.name = name
self.berat = berat
self.tglLahir = tglLahir
self.Tinggi = Tinggi
self.golDarah = golDarah
self.Telp = Telp
let pasienListDictionary = dictionary["patientNote"] as? [JSONDictionary]
if let dictionaries = pasienListDictionary {
self.patientNote = dictionaries.compactMap(PatientNote.init)
}
}
func toDictionary() -> [String:Any] { // ini buat dictionary buat convery object jd string:any, jd biar ga ngubah satu2 kl ada yg salah gituu
return ["Name":self.name, "BeratBadan":self.berat, "TanggalLahir":self.tglLahir, "TinggiBadan":self.Tinggi, "golDarah":self.golDarah, "Telefon":self.Telp, "patientNote":self.patientNote.map{ patientNote in
return patientNote.toDictionary()
}]
}
}
and this is my firebase :
[![Firebase][1]][1]
for the starters i just need to show my name into my tableview which in this case i cant even show the name data in my tableview
i cant seems to find out why the data wont show in my tableview....xcode not showing error
anyone can help me? thanks
firebase Json
"afipermanalivecom" : {
"Apiyyy" : {
"BeratBadan" : "",
"Name" : "Apiyyy",
"TanggalLahir" : "20-05-2020",
"Telefon" : "",
"TinggiBadan" : "",
"golDarah" : "A+"
},
"CocaCola" : {
"BeratBadan" : "80",
"Name" : "CocaCola",
"TanggalLahir" : "20-06-2020",
"Telefon" : "0878099996049",
"TinggiBadan" : "190",
"golDarah" : "A-"
},
"Jamsey" : {
"BeratBadan" : "",
"Name" : "Jamsey",
"TanggalLahir" : "19-06-2020",
"Telefon" : "",
"TinggiBadan" : "",
"golDarah" : "A-"
}
},
"puffygmailcom" : {
"Batman" : {
"Name" : "Batman"
},
"Stitchh" : {
"Name" : "Stitchh"
}
}
From the code and structure in the question it appears there's a list of doctors and patients with the patients being child nodes of the doctor. I'll post a solution and then some important recommendations about changes.
Here's the existing Firebase structure. Note that we are NOT using email addresses as node keys - it's a lot of extra work and if the email address changes, the entire database will have be scanned, nodes read, deleted and re-written. Dynamic node keys (ones that could change, like an email) should instead be generated with .childByAutoId - I am using doctor_0, doctor_1 etc for readability.
{
"doctor_0" : {
"name" : "Dr. Doolittle",
"patient_list" : {
"patient_0" : {
"blood_type" : "O-",
"name" : "Henry"
},
"patient_1" : {
"blood_type" : "AB-",
"name" : "Leroy"
}
}
},
"doctor_1" : {
"name" : "Dr. McCoy",
"patient_list" : {
"patient_2" : {
"blood_type" : "O+",
"name" : "Steve"
}
}
}
}
I have two classes to hold this data, a DoctorClass and PatientClass with the Patient class being an array within the DoctorClass. Note that a Doctor may not have any Patients so I am treating that as an optional.
class DoctorClass {
var doc_id = ""
var doc_name = ""
var patients = [PatientClass]()
convenience init(withId: String, andName: String, maybePatientList: DataSnapshot?) {
self.init()
self.doc_id = withId
self.doc_name = andName
if let patientList = maybePatientList {
let allPatientsSnap = patientList.children.allObjects as! [DataSnapshot]
for patientSnap in allPatientsSnap {
let patient = PatientClass(patientSnap: patientSnap)
self.patients.append(patient)
}
}
}
}
class PatientClass {
var patient_id = ""
var patient_name = ""
var blood_type = ""
convenience init(patientSnap: DataSnapshot) {
self.init()
self.patient_id = patientSnap.key
self.patient_name = patientSnap.childSnapshot(forPath: "name").value as? String ?? "No Name"
self.blood_type = patientSnap.childSnapshot(forPath: "blood_type").value as? String ?? "No blood type"
}
}
and finally the code to read in all of the doctors and populate their patient array with their patients.
var docAndPatientList = [DoctorClass]()
func loadDoctorsAndPatients() {
let doctorsRef = self.ref.child("doctors") //self.ref points to *my* firebase
doctorsRef.observeSingleEvent(of: .value, with: { snapshot in
let allDoctorsSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for docSnap in allDoctorsSnapshot {
let docId = docSnap.key
let docName = docSnap.childSnapshot(forPath: "name").value as? String ?? ""
let patientSnap = docSnap.childSnapshot(forPath: "patient_list")
let doc = DoctorClass(withId: docId, andName: docName, maybePatientList: patientSnap)
self.docAndPatientList.append(doc)
}
})
}
and then let's print them out
func printDoctorsAndPatients() {
self.docAndPatientList.forEach { doctor in
print("Dr: \(doctor.doc_name)")
for patient in doctor.patients {
print(" patient: \(patient.patient_name) bloodtype: \(patient.blood_type)")
}
}
}
and the output
Dr: Dr. Doolittle
patient: Henry bloodtype: O-
patient: Leroy bloodtype: AB-
Dr: Dr. McCoy
patient: Steve bloodtype: O+
That will work with the existing structure but what if, for example, a patient has two doctors? Or what if we want to query Firebase for all patients that have blood type O-? It's not going to work (easily) with that structure.
Here's a better plan
root_ref
doctors
doctor_0
name : "Dr. Doolittle"
patients
patient_0 : true
patient_1 : true
doctor_1
name : "Dr. McCoy"
patients
patient_2 : true
and patients
root_ref
patients
patient_0
blood_type : "O-"
doctors:
doctor_0: true
name : "Henry"
patient_1
blood_type : "AB-"
doctors:
doctor_0: true
name : "Leroy"
patient_2
blood_type : "O+"
doctors:
doctor_1: true
name : "Steve"
This structure provides way more query flexibility and scaleability.
Just some tips and perhaps a solution,
I would recommend using firebase Cloud instead of firebase real time firebase, its much fast and more reliable especially if your trying to query data from arrays or dictionary, I can see you are trying to retrieve data from a dictionary, one thing you want to note is that firebase stores your swift dictionary as an objective C dictionary, so thats one thing you want to note! Try to check if you used the correct reuse identifiers.
Let me know if you still can't get it!
If you would like to return a list of data, you would have to use .childAdded instead of .value
So, your code would be something like this:
self.rootRef.child(self.user.emailWithoutSpecialChar).observe(.childAdded) { (snapshot) in
// do your stuff here
}
*salam sesama orang Indonesia :)

custom class data not showing in to the tableview in swift

hi am fetching from data from firebase and stored into custom class and displaying into the tableview, when I displaying tableview its not showing empty but when I am calling with another array data its working fine
class datapass {
var fullName : String?
var status : String?
var dateAndTimeofVisit :String?
var profilephot :String?
var uid :String?
var inviterUID: String?
init(fullname:String?,status:String?,dateAndTimeofVisit:String?,profilephot:String,uid:String?,inviterUID:String?) {
self.fullName = fullname
self.status = status
self.dateAndTimeofVisit = dateAndTimeofVisit
self.profilephot = profilephot
self.uid = uid
self.inviterUID = inviterUID
}
}
inside viewdidload
var datapassval = [datapass]()
HandedDataRef = Database.database().reference()
.child(Constants.FIREBASE_CHILD_VISITORS)
.child(Constants.FIREBASE_CHILD_PRE_APPROVED_VISITORS).child("-LHO1TuRZTKCZV5Mli13")
HandedDataRef?.observeSingleEvent(of: .value, with: {(snapshot) in
print("snapshot values",snapshot)
if snapshot.exists() {
let visitorData = snapshot.value as? [String: AnyObject]
print("visitordata",visitorData as Any)
let dateAndTimeOfVisit = visitorData?[VisitorListFBKeys.dateAndTimeOfVisit.key] as? String
let fullName = visitorData?[VisitorListFBKeys.fullName.key] as? String
let inviterUID = visitorData?[VisitorListFBKeys.inviterUID.key] as? String
let mobileNumber = visitorData?[VisitorListFBKeys.mobileNumber.key] as? String
let profilePhoto = visitorData?[VisitorListFBKeys.profilePhoto.key] as? String
let status = visitorData?[VisitorListFBKeys.status.key] as? String
let uid = visitorData?[VisitorListFBKeys.uid.key] as? String
self.datapassval.append(datapass.init(fullname: fullName, status: status , dateAndTimeofVisit: dateAndTimeOfVisit, profilephot: profilePhoto!, uid: uid, inviterUID: inviterUID))
}
})
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datapassval.count //count getting 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! HandedThingsToGuestTableViewCell
let datamy = datapassval[indexPath.row]
print("datamy",datamy)
cell.lbl_VisiterName.text = datamy.fullName
}
its not showing any thing how to display custom class data where I did mistake
You need to reload the table
self.datapassval.append(datapass.init(fullname: fullName, status: status , dateAndTimeofVisit: dateAndTimeOfVisit, profilephot: profilePhoto!, uid: uid, inviterUID: inviterUID))
self.tableView.reloadData()

Not able to save data from Firebase database to an Array

*I'm fairly new to swift
I'm currently using Swift 4, Xcode 9, and Firebase. My goal is to create an app that stores data in a list, displays it in a table view, and allows the user to add more data to the list. I'm stuck on the displaying data part, I created a function that is supposed to get the data from the database, then add it into an array so that I can display individual parts of it on a custom table view cell. Here's my code:
class OrdersPage: UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return orders.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "orderCell", for: indexPath) as! OrderCell
cell.setOrder(order: orders[indexPath.row])
print("Adding new cell")
return cell
}
#IBOutlet weak var tableView: UITableView!
var ref: DatabaseReference!
var orders = [Order]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.ref = Database.database().reference()
orders = getOrders()
}
func getOrders() -> [Order] {
var tempArray = [Order]()
ref.child("Orders").observe(.value) { (snapshot) in
for child in snapshot.children {
let orderDB = child as! DataSnapshot
let orderDict = orderDB.value as! [String: Any]
let name = orderDict["name"] as! String
let date = orderDict["date"] as! String
let time = orderDict["time"] as! String
let hotel = orderDict["hotel"] as! String
let room = orderDict["room"] as! String
let airport = orderDict["airport"] as! String
let agent = orderDict["agent"] as! String
let price = orderDict["price"] as! String
//let submitted = orderDict["submitted"] as! String
tempArray.append(Order(name: name, date: date, time: time, hotel: hotel, room: room, airport: airport, agent: agent, price: price))
}
}
return tempArray
}
Based off of my testing, the issue is that the orders array doesn't contain anything when the numberOfRowsInSection is called so it doesn't create any cells in the table view. I'm not sure why it's not working as it should and have been stuck on this for quite some time now, any help is appreciated.
getOrders() is Asynchronous call so you need to reload your table after you got data from server.
Here is the way you can achieve that.
Replace:
func getOrders() -> [Order]
with
func getOrders()
And your getOrders method will look like:
func getOrders() {
ref.child("Orders").observe(.value) { (snapshot) in
for child in snapshot.children {
let orderDB = child as! DataSnapshot
let orderDict = orderDB.value as! [String: Any]
let name = orderDict["name"] as! String
let date = orderDict["date"] as! String
let time = orderDict["time"] as! String
let hotel = orderDict["hotel"] as! String
let room = orderDict["room"] as! String
let airport = orderDict["airport"] as! String
let agent = orderDict["agent"] as! String
let price = orderDict["price"] as! String
//let submitted = orderDict["submitted"] as! String
//Add your data into array
self.orders.append(Order(name: name, date: date, time: time, hotel: hotel, room: room, airport: airport, agent: agent, price: price))
}
//Reload your tableView here
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
I have updated inner code. Check comments.
Now in your viewDidLoad method Replace:
orders = getOrders()
With
getOrders()
You can use didSet during define your variable of self.orders for reloading UITableView
Here your table will automatically reload when any data is assigned to self.orders
Replace your declaration
var orders = [Order]()
with below code
var orders : [Order] = [] {
didSet {
tableView.reloadData()
}
}

TableView Public To all Users

I am creating a chat room app. Currently, when users signs in they are given their own table view to upload data too.
Instead of each user having their own personal table view I would like all users to be connected to one (public) table view so everyone can see what's posted. Hence a chat room app.
These are 3 separate logins and what it looks like for each user when they post a message:
This is what I want. To have each tableview cell represent a different message from a different user. All publicly viewed on one tableview. Not on separate table views:
How can I make the table view public? When I log in as a different user I would like the previous message to still be there from each user. Hence a chat room.
{
"rules": {
"Users":{
".read": "true",
".write": "true"
},
"general_room" : {
".read": "true",
".write": "true"
}
}
}
GeneralChatroom.swift
import UIKit
import Foundation
import Firebase
import FirebaseDatabase
import FirebaseStorage
struct postStruct {
let username : String!
let message : String!
let photoURL : String!
}
class GeneralChatroom: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
#IBOutlet weak var messageTextField: UITextField!
var generalRoomDataArr = [postStruct]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140
let ref = FIRDatabase.database().reference()
let userID = FIRAuth.auth()?.currentUser?.uid
ref.child("general_room").child("chat").child(userID!).queryOrderedByKey().observe(.childAdded, with: {snapshot in
let snapDict = snapshot.value as? NSDictionary
let username = snapDict?["Username"] as? String ?? ""
let message = snapDict?["Message"] as? String ?? ""
let firebaseUserPhotoURL = snapDict?["photo_url"] as? String ?? ""
self.generalRoomDataArr.insert(postStruct(username: username, message: message, photoURL: firebaseUserPhotoURL), at: 0)
self.tableView.reloadData()
})
}
#IBAction func backButtonPressed(_ sender: UIButton) {
self.performSegue(withIdentifier: "BackToRoom", sender: nil)
}
//Message Send button is pressed data uploaded to firebase
#IBAction func sendButtonPressed(_ sender: UIButton) {
let message : String = self.messageTextField.text!
UploadGeneralChatRoom(message: message) //upload to general_room
self.messageTextField.text = nil
messageTextField.resignFirstResponder()//Quit keyboard
self.tableView.reloadData() //Reload tableView
//UploadUserData() //Update Rank in database
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return generalRoomDataArr.count // your number of cell here
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let usernameLabel = cell?.viewWithTag(1) as! UILabel
usernameLabel.text = generalRoomDataArr[indexPath.row].username
let messageLabel = cell?.viewWithTag(2) as! UILabel
messageLabel.numberOfLines=0 // line wrap
messageLabel.lineBreakMode = NSLineBreakMode.byWordWrapping
messageLabel.text = generalRoomDataArr[indexPath.row].message
//initialize UI Profile Image
let imageView = cell?.viewWithTag(3) as! UIImageView
//Make Porfile Image Cirlce
imageView.layer.cornerRadius = imageView.frame.size.width/2
imageView.clipsToBounds = true
//User Profile image in tableview
if generalRoomDataArr[indexPath.row].photoURL != nil
{
//let imageView = cell?.viewWithTag(3) as! UIImageView
if let url = NSURL(string: generalRoomDataArr[indexPath.row].photoURL) {
if let data = NSData(contentsOf: url as URL) {
imageView.image = UIImage(data: data as Data)
}
}
}
// your cell coding
return cell!
}
}//END CLASS
Upload to firebase
import Foundation
import Firebase
import FirebaseDatabase
import FirebaseStorage
func UploadGeneralChatRoom(message : String) {
//Firebase Initialization
var ref: FIRDatabaseReference!
//var storage: FIRStorageReference!
let userID = FIRAuth.auth()?.currentUser?.uid
ref = FIRDatabase.database().reference()
//storage = FIRStorage.storage().reference()
//Get Data from database resend to database
ref.child("Users").child(userID!).observeSingleEvent(of: .value, with: {(snapshot) in
let snapDict = snapshot.value as? NSDictionary
let username = snapDict?["Username"] as? String ?? ""
let firebaseUserPhotoURL = snapDict?["photo_url"] as? String ?? ""
ref.child("general_room").child("chat").child(userID!).childByAutoId().setValue(["Username": username, "uid": userID!, "Message" : message, "photo_url" : firebaseUserPhotoURL])
})
}
I don't know how your firebase database is setup but you are posting to child("Users").child(userID!)
but reading from
child("general_room").child("chat").child(userID!)
You would need to read and write to the same location.
Also:
try to safely unwrap your optional values:
if let userId = userID {
ref.child("Users").child(userId).observeSingleEvent(of: .value, with: {(snapshot) in
let snapDict = snapshot.value as? NSDictionary
let username = snapDict?["Username"] as? String ?? ""
let firebaseUserPhotoURL = snapDict?["photo_url"] as? String ?? ""
ref.child("general_room").child("chat").child(userID!).childByAutoId().setValue(["Username": username, "uid": userID!, "Message" : message, "photo_url" : firebaseUserPhotoURL])
})
}

Iterating through all nodes in node in Firebase

I've got sample structure that looks like this:
I want to add every item to the array of items I've created. So as you can see the downloadListData function can only download information from Apples, because I don't know how to get to Apples, Bread and Eggs in the same time without writing a lot of code. I was trying loops and arrays and it didn't work. Moreovery I was analyzing examples on the Internet and I didn't get the answer which worked in my app.
ListItem.swift:
import Foundation
import Firebase
struct ListItem{
var name : String!
var addedBy : String!
var completed : Bool!
init(name: String, addedBy: String, completed: Bool){
self.name = name
self.addedBy = addedBy
self.completed = completed
}
}
part of my ViewController.swift:
import UIKit
import Firebase
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var rootRef : FIRDatabaseReference!
var listDataRef : FIRDatabaseReference!
var refHandle: UInt!
var listItemsDownload = [ListItem]()
//test vars
var user : String!
#IBOutlet weak var plusButton: UIButton!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
user = "test#me.com"
rootRef = FIRDatabase.database().reference()
listDataRef = rootRef.child("listData")
downloadListData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listItemsDownload.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CellData{
print("cellForRowAt")
let items = listItemsDownload[indexPath.row]
// testing the tableView
cell.nameLabel?.text = items.name
}
return cell
} else{
print("else")
return CellData()
}
}
func downloadListData(){
print(" ### DOWNLOAD ###")
self.listDataRef.observe(FIRDataEventType.value, with: { snapshot in
var downloadedName : String!
var downloadedUser : String!
var downloadedComplete : Bool!
if let dict = snapshot.value as? Dictionary<String, Any>{
if let apples = dict["Apples"] as? Dictionary<String, Any>{
if let name = apples["name"] as? String{
downloadedName = name
}
if let user = apples["addedBy"] as? String{
downloadedUser = user
}
if let completed = apples["completed"] as? Bool{
downloadedComplete = completed
}
let item = ListItem(name: downloadedName, addedBy: downloadedUser, completed: downloadedComplete)
self.listItemsDownload.append(item)
self.tableView.reloadData()
}
}
})
}
So probably I have to change only this line to get to different values and not only Apples (if let apples = dict["Apples"] as? Dictionary<String, Any>{
Just use a separate method which you can call with your different keys like this:
func downloadListData(){
print(" ### DOWNLOAD ###")
self.listDataRef.observe(FIRDataEventType.value, with: { snapshot in
addAllItemsFromSnapshotWithKey(snapshot, key: "Apples")
addAllItemsFromSnapshotWithKey(snapshot, key: "Bread")
addAllItemsFromSnapshotWithKey(snapshot, key: "Eggs")
// You need to reload your table view on the main thread, since it's an asynchronous call to firebase
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
func addAllItemsFromSnapshotWithKey(_ snapshot: FIRDataSnapshot, key: String) {
var downloadedName : String!
var downloadedUser : String!
var downloadedComplete : Bool!
if let dict = snapshot.value as? Dictionary<String, Any>{
if let values = dict[key] as? Dictionary<String, Any> {
if let name = values["name"] as? String{
downloadedName = name
}
if let user = values["addedBy"] as? String{
downloadedUser = user
}
if let completed = values["completed"] as? Bool{
downloadedComplete = completed
}
let item = ListItem(name: downloadedName, addedBy: downloadedUser, completed: downloadedComplete)
self.listItemsDownload.append(item)
}
}
}
Update for a more scalable solution. Just loop through all keys
func downloadListData(){
print(" ### DOWNLOAD ###")
self.listDataRef.observe(FIRDataEventType.value, with: { snapshot in
var downloadedName : String!
var downloadedUser : String!
var downloadedComplete : Bool!
if let dict = snapshot.value as? Dictionary<String, Any>{
for key in dict.keys {
if let values = dict[key] as? Dictionary<String, Any> {
if let name = values["name"] as? String{
downloadedName = name
}
if let user = values["addedBy"] as? String{
downloadedUser = user
}
if let completed = values["completed"] as? Bool{
downloadedComplete = completed
}
let item = ListItem(name: downloadedName, addedBy: downloadedUser, completed: downloadedComplete)
self.listItemsDownload.append(item)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
})
}

Resources