How to read data from firebase, block with doesn't work? - swift

I try to read data from firebase. I've made observeSingleEvent, but block "with" not works, why?
I try to debug and I notice that block with doesn't work.
userID has correct ID
and reference also correct
var ref: DatabaseReference!
var snapData: NSDictionary?
var nameString = [String]()
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
loadData()
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "indentifire")
view.addSubview(table)
// Do any additional setup after loading the view.
}
// ---------------------------------------------------
//loading data from FireBase
func loadData() {
let userID = Auth.auth().currentUser?.uid
ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
self.snapData = snapshot.value as? NSDictionary
})
}
// delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var temp = 0
for (_,val) in snapData! {
if val as? String == "false" {
temp += 1
nameString.append(val as! String)
}
}
return temp
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "indentifire", for: indexPath)
cell.textLabel!.text = nameString[indexPath.row]
return cell
}```
this is my database
![photo](https://imgur.com/a/0UzOPJ7

The database operations work asynchronously. Map the data in loadData and reload the table view
func loadData() {
let userID = Auth.auth().currentUser?.uid
ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
if let snapData = snapshot.value as? [String:Any] {
self.nameString = snapData.values.compactMap {$0 as? String}
DispatchQueue.main.async {
self.table.reloadData()
}
}
})
}
And in numberOfRowsInSection just return the number of items in nameString
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nameString.count
}

Related

Retrieve child key one by one and display in label swift

I'm trying to retrieve the child in Firebase and print them EACH in a label but when I'm retrieving the key its printing all at the same time. I'm still learning on the go so here's what i tried:
func retrieve(){
let userId = Auth.auth().currentUser?.uid
let intakeRef = Database.database().reference().child("Users").child(userId!).child("Intake")
intakeRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let intake = snapshot.value{
self.ref.child("Attendance").child("Checkin").child(intake as! String).child(userId!).child("BM050-3-3-IMNPD").observe(.value, with: { (snapshot) in
for child in snapshot.children{
let key = (child as AnyObject).key as String
print(key)
label.text = key
}
})
}
}) { (Error) in
print("unable to retrieve name from nameRef")
}
}
The code I tried like i said is printing all at the same time. But i would like to print each one in a separate label. Any help would really be appreciated!
You'll of course need to create a tableViewController and link it up to a TableView and assign your cell its own identifier, but this is a good outline of what you'd need to do in your own tableViewController:
class tableViewController: UITableViewController {
var dataArray = [String]()
var ref = Database.database().reference() //You didn't include your delcaration of ref in your code, so don't use this, just use the one you were already using.
override func viewDidLoad() {
super.viewDidLoad()
retrieve()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let data = dataArray[indexPath.row]
cell.textLabel?.text = data
return cell
}
func retrieve(){
let userId = Auth.auth().currentUser?.uid
let intakeRef = Database.database().reference().child("Users").child(userId!).child("Intake")
intakeRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let intake = snapshot.value{
self.ref.child("Attendance").child("Checkin").child(intake as! String).child(userId!).child("BM050-3-3-IMNPD").observe(.value, with: { (snapshot) in
for child in snapshot.children{
let key = (child as AnyObject).key as String
self.dataArray.append(key)
}
})
self.tableView.reloadData()
}
}) { (Error) in
print("unable to retrieve name from nameRef")
}
}
}
Again you'll need to create your own UItableView, link it up to a UITableViewController, assign your own cell reuse identifier and make sure that cellForRowAt has the correct reuse identifier in it, and you'll need to change the ref variable in my provided code to the ref that you need to use.

Firebase tableview not populating, Swift

I have data in my db and can search for an individual record, that's working fine. But when I try to simply populate a tableview with all of the db records its not receiving/displaying any data.
here is my code:
struct drinkStruct {
let pub: String!
let rating: String!
let price: String!
}
override func viewDidLoad() {
super.viewDidLoad()
loadDrinks()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func homeClicked(_ sender: Any) {
homeClicked()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].pub
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].rating
let label3 = cell.viewWithTag(3) as! UILabel
label3.text = posts[indexPath.row].price
return cell
}
func loadDrinks(){
let databaseRef = Database.database().reference().child("Drinks")
ref = Database.database().reference()
databaseRef.queryOrderedByKey().observe(.childAdded, with: { (snapshot) in
if let valueDictionary = snapshot.value as? [AnyHashable:String]
{
let pub = valueDictionary["pub"]
let rating = valueDictionary["rating"]
let price = valueDictionary["price"]
self.posts.insert(drinkStruct(pub: pub, rating: rating, price: price), at: 0)
}
})
self.tableview.reloadData()
}
And here is my db structure:
Am I doing something blatantly obviously wrong? Or can anyone see what's causing no data to load?
There are no errors/unused variables etc etc.
Thanks in advance!
I think the following should do the job.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
//getting a reference to the node //
databaseRef = Database.database().reference().child("Drinks")
//observing the data changes
databaseRef.observe(DataEventType.value, with: { (snapshot) in
if snapshot.childrenCount > 0 {
// clearing the list //
self.posts.removeAll()
// iterating through all the values //
for drinks in snapshot.children.allObjects as! [DataSnapshot] {
let drinkObject = drinks.value as! [String: AnyObject]
let drinkPub = drinkObject["pub"]
let drinkRating = drinkObject["rating"]
let drinkPrice = drinkObject["price"]
//creating a drinkStruct object with the model //
let drinkModel = drinkStruct(pub: drinkPub as! String?, rating: drinkRating as! String?, price: drinkPrice as! String?)
//appending it to list
self.posts.append(drinkModel)
}
// reloading data //
self.tableView.reloadData()
}
})
}
var posts = [drinkStruct]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourCustomTableViewCell
let drink: drinkStruct
drink = posts[indexPath.row]
cell.label1.text = drink.pub
cell.label2.text = drink.rating
cell.label3.text = drink.price
return cell
}
}
For the newbie that's here in my footsteps, I solved this by doing a lot of things.
You need to create the tableview & cell layout in the storyboard. Then you need a cell class that dictates/assigns what's happening in each cell(imageviews, labels etc) as well as a model class for whatever you're looking up, whatever the object may be.
This is the code I used for my function in which I populate the info in the cells with the data from Firebase:
func loadDrinks(){
Database.database().reference().child("Drinks").observe(.childAdded) { (snapshot: DataSnapshot) in
if let dict = snapshot.value as? [String: Any] {
let pub = dict["pub"] as! String
let rating = dict["rating"] as! String
let price = dict["price"] as! String
let drink = Drink(pub: pub.capitalized, rating: rating.capitalized, price: price.capitalized)
self.drinks.append(drink)
print(self.drinks)
self.tableview.reloadData()
}
}
}
This was a Newbie 101 question - my bad.

I want to get firestore data in dequeueReusableCell

I rewrote all the text and now I got the code I wanted to realize.
It can not be displayed on the tableCell, and the layout also collapses. I am sorry that the code and the body I wrote are not explained enough.
guard let userID = Auth.auth (). currentUser? .uid I want to always acquire userID with else {return}.
// guard let docSnapshot = querySnapshot, document.exists else {return}
Since an error occurs, it is commented out.
Within viewidLoad of UIViewController
var profDict: [ProfDic] = [] is in the UIViewController.
profUIView is being added to UIViewController.
func getFirebaseData() {
db = Firestore.firestore()
guard let userID = Auth.auth().currentUser?.uid else {return}
let ref = db.collection("users").document(userID)
ref.getDocument{ (document, error) in
if let document = document {
// guard let docSnapshot = querySnapshot, document.exists else {return}
if let prof = ProfDic(dictionary: document.data()!) {
self.profDict.append(prof)
print("Document data \(document.data())")
}
}else{
print("Document does not exist")
}
self.profUIView.tableView1.reloadData()
}
}
tableView1 has been added to ProfUIView.
class ProfUIView: UIView, UITableViewDelegate, UITableViewDataSource {
//omission...
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .blue
addSubview(tableView1)
tableView1.anchor(top: //omission...
sections = [
Section(type: .prof_Sec, items: [.prof]),
Section(type: .link_Sec, items: [.link]),
Section(type: .hoge_Sec, items: [.hoge0])
]
tableView1.register(TableCell0.self, forCellReuseIdentifier: TableCellId0)
tableView1.register(TableCell3.self, forCellReuseIdentifier: TableCellId3)
tableView1.register(TableCell5.self, forCellReuseIdentifier: TableCellId5)
tableView1.delegate = self
tableView1.dataSource = self
}
var tableView1:UITableView = {
let table = UITableView()
table.backgroundColor = .gray
return table
}()
//omission
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (baseVC?.profDict.count)!//sections[section].items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch sections[indexPath.section].items[indexPath.row] {
case .prof:
let cell0 = tableView.dequeueReusableCell(withIdentifier: TableCellId0, for: indexPath) as? TableCell0
cell0?.nameLabel.text = baseVC?.profDict[indexPath.row].userName
return cell0!
}
//omission...
}
}
Additional notes
import Foundation
import FirebaseFirestore
struct ProfDic {
var userName :String
var dictionary:[String:Any] {
return
["userName" : userName
]
}
}
extension ProfDic {
init?(dictionary:[String:Any]) {
guard let userName = dictionary["userName"] as? String
else {return nil}
self.init(userName: userName as String)
}
}
enter image description here
First create an empty array of ProfDic elements:
var profDict: [ProfDic] = []
Then create a function to load your Firebase Data:
func getFirebaseData() {
db = Firestore.firestore()
let userRef = db.collection("users").getDocuments() {
[weak self] (querySnapshot, error) in
for document in querySnapshot!.documents {
guard let docSnapshot = docSnapshot, docSnapshot.exists else {return}
if let prof = ProfDic(dictionary: docSnapshot.data()!) {
profDict.append(prof)
}
}
tableView.reloadData()
}
}
Call this function in viewDidLoad or viewDidAppear.
Then in tableView cellForRowAt you access your data like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch sections[indexPath.section].items[indexPath.row] {
case .prof:
let cell = tableView.dequeueReusableCell(withIdentifier: TableCellId, for: indexPath) as? TableCell
cell?.nameLabel.text = profDict[indexPath.row].userName
return cell!
}
}
EDIT:
Also in numberOfRowsInSection:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return profDict.count
}

tableview not displaying firebase users

I am having a problem with my tableview not showing prototype cells. I have properly named each cell and Identifier. Here is my current code: (Thanks!)
import UIKit
import Firebase
import FirebaseDatabase
class UsersTableViewController: UITableViewController {
#IBOutlet var tableview: UITableView!
var ref: DatabaseReference!
var user = [User]()
override func viewDidLoad() {
super.viewDidLoad()
getusers()
// Do any additional setup after loading the view.
}
func getusers() {
let ref = Database.database().reference()
ref.child("users").child(Auth.auth().currentUser!.uid).queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in
let users = snapshot.value as? [String : AnyObject] ?? [:]
for (_, value) in users
{
if let uid = users["uid"] as? String
{
if uid != Auth.auth().currentUser!.uid
{
let showUser = User()
if let fullname = users["fullname"] as? String, let imagePath = users["urlImage"] as? String
{
showUser.fullname = fullname
showUser.imagePath = imagePath
showUser.userID = uid
self.user.append(showUser)
}
}
}
}
self.tableview.reloadData()
})
ref.removeAllObservers()
}
override func numberOfSections(in tableview: UITableView) -> Int {
return 1
}
override func tableView(_ tableview: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! UserCell
cell.nameLabel.text = self.user[indexPath.row].fullname
cell.UserID = self.user[indexPath.row].userID
cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
checkFollowing(indexPath: indexPath)
return cell
}
override func tableView(_ tableview: UITableView, numberOfRowsInSection section: Int) -> Int {
return user.count
}
override func tableView(_ tableview: UITableView, didSelectRowAt indexPath: IndexPath) {
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference()
let key = ref.child("users").childByAutoId().key
var isFollower = false
ref.child("users").child(uid).child("following").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
if let following = snapshot.value as? [String : AnyObject] {
for (ke, value) in following {
if value as! String == self.user[indexPath.row].userID {
isFollower = true
ref.child("users").child(uid).child("following/\(ke)").removeValue()
ref.child("users").child(self.user[indexPath.row].userID).child("followers/\(ke)").removeValue()
self.tableview.cellForRow(at: indexPath)?.accessoryType = .none
}
}
}
if !isFollower {
let following = ["following/\(key)" : self.user[indexPath.row].userID]
let followers = ["followers/\(key)" : uid]
ref.child("users").child(uid).updateChildValues(following)
ref.child("users").child(self.user[indexPath.row].userID).updateChildValues(followers)
self.tableview.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
})
ref.removeAllObservers()
}
func checkFollowing(indexPath: IndexPath) {
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference()
ref.child("users").child(uid).child("following").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
if let following = snapshot.value as? [String : AnyObject] {
for (_, value) in following {
if value as! String == self.user[indexPath.row].userID {
self.tableview.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
}
}
})
ref.removeAllObservers()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
I am currently using Google's Firebase API for user storage. In this code I am trying to fetch users to my tableview, only my table view is not displaying any information. Thank you in advance if you are able to help!
Remove ref.removeAllObservers() line. Method observeSingleEvent removes observers automatically after completion execution. So in your case ref.removeAllObservers() can remove them before completion invokes and therefore any code in completion doesn't execute.

Swift - How can I group value array (from dictonary) to multiple section

I am a beginner in Swift. How can I group array list from dictionary? I tried, but it show all list into one section. I can't group, list, sort and show list by the same group.
Image 1
But I can do like this,
Image 2
Here's the code for Todolist array
import Foundation
import Firebase
import FirebaseDatabase
struct TodoList {
var title:String!
var content:String!
var username:String!
var dateLabel:String!
var ref : FIRDatabaseReference?
var key: String!
var picNoteStringUrl : String!
var userImageViewStringUrl : String!
var postId: String!
init(title:String,content:String,username:String,picNoteStringUrl : String,userImageViewStringUrl : String,postId: String,dateLabel:String,key:String="") {
self.title=title
self.content=content
self.username = username
self.dateLabel = dateLabel
self.key=key
self.userImageViewStringUrl = userImageViewStringUrl
self.picNoteStringUrl = picNoteStringUrl
self.postId = postId
self.ref=FIRDatabase.database().reference()
}
init(snapshot:FIRDataSnapshot) {
let value = snapshot.value as? [String: AnyObject]
title = value?["title"] as! String
content = value?["content"] as! String
username = value?["username"] as! String
postId = value?["postId"] as! String
picNoteStringUrl = value?["picNoteStringUrl"] as! String
userImageViewStringUrl = value?["userImageViewStringUrl"] as! String
dateLabel = value?["dateLabel"] as! String
key = snapshot.key
ref = snapshot.ref
}
func toAnyObject() -> [String: AnyObject] {
return ["title": title as AnyObject, "content": content as AnyObject,"username": username as AnyObject,"picNoteStringUrl":picNoteStringUrl as AnyObject,"userImageViewStringUrl": userImageViewStringUrl as AnyObject,"postId":postId as AnyObject,"dateLabel" : dateLabel as AnyObject]
}
}
And here's my code for TableViewController
class TodoListTableViewController: UITableViewController{
var storageRef: FIRStorageReference!
var databaseRef : FIRDatabaseReference!
var todoArray:[TodoList] = []
override func viewDidLoad() {
super.viewDidLoad()
if FIRAuth.auth()?.currentUser==nil{
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Home")
self.present(vc,animated: true,completion: nil)
}
else{
let uid = FIRAuth.auth()?.currentUser?.uid
let databaseRef = FIRDatabase.database().reference().child("allTasks").child(uid!)
databaseRef.observe(.value, with: { (snapshot) in
var newItems = [TodoList]()
for item in snapshot.children {
let newTodo = TodoList(snapshot: item as! FIRDataSnapshot)
let letter = newTodo.dateLabel
newItems.insert(newTodo, at: 0)
}
self.todoArray = newItems
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}) { (error) in
print(error.localizedDescription)
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return todoArray.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let todoLine = todoArray[section]
return todoArray.count
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
let todoLine = todoArray[section]
return todoLine.dateLabel
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TodoTableViewCell
cell.todoItemName.text = self.todoArray[indexPath.row].title
cell.todoDescription.text = self.todoArray[indexPath.row].content
cell.usernameLabel.text = self.todoArray[indexPath.row].username
let picNoteStringUrl = self.todoArray[indexPath.row].picNoteStringUrl
let userImageViewStringUrl = self.todoArray[indexPath.row].userImageViewStringUrl
FIRStorage.storage().reference(forURL: picNoteStringUrl!).data(withMaxSize: 10 * 1024 * 1024, completion: { (data, error) in
if error == nil {
DispatchQueue.main.async(execute: {
if let picNoteStringUrl = UIImage(data:data!) {
cell.picNote.image = picNoteStringUrl
print("testpass",picNoteStringUrl)
}
})
}else {
print(error!.localizedDescription,"555")
}
})
FIRStorage.storage().reference(forURL: userImageViewStringUrl!).data(withMaxSize: 10 * 1024 * 1024, completion: { (data, error) in
if error == nil {
DispatchQueue.main.async(execute: {
if let userImageViewStringUrl = UIImage(data:data!) {
cell.userImageView.image = userImageViewStringUrl
print("testpass",userImageViewStringUrl)
}
})
}else {
print(error!.localizedDescription,"555")
}
})
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath:IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .default, title: "\u{267A}\n Delete") { action, index in
print("more button tapped")
let ref = self.todoArray[indexPath.row].ref
ref?.removeValue()
self.todoArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
delete.backgroundColor = UIColor.red
let check = UITableViewRowAction(style: .default, title: "\u{2611}\n check") { action, index in
print("edit button tapped")
}
check.backgroundColor = UIColor.orange
return [check, delete]
}
}
}
}
You have to organize your data by section first. I don't see that happening since you simply add all received items into one array.
Based on the screenshot you have provided and the project, it looks as if you are trying to display todo items by date where each section is for a different date. And as far as I can tell, your date value is in the dateLabel property.
If all of the above is correct, then you would need to convert the dateLabel property, which is a String, to an actual Date value so that you can work with the individual dates. Or, depending on how the date string is set up, you might be able to do the same thing by getting just the date component of the string. For example, if your date strings are like "2017-03-31 10:55am" or something, just getting the "2017-03-31" part should allow you to organize the todo items so that all items for the same date can be easily identified.
Once you do that, you have to set up some sort of a structure - if you go with date strings, then a dictionary might work - where you can identify all todo items for a given date. For example, if you have just the date extracted as a string (like "2017-03-31") then you could set up something like this:
var dates = [String]()
var todoItems = [String:[TodoList]]()
The above means that for one string value (which would be a date), you'd have an array of TodoList items. The dates array would be just a convenience so that you can sort the date strings the way you want.
Once you have that, you can modify your table delegate methods to get the count of items in dates to get the sections and the relevant TodoList for each row. Like this:
override func numberOfSections(in tableView: UITableView) -> Int {
return dates.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let date = dates[section]
let array = todoItems[date]
return array.count
}
Hopefully, the above makes sense :)