Swift load firebase database data when there is a change in data - swift

I have a tableview set up that is fetching my firebase database info like so below. How do I set up a listener to look for any new database changes? At the moment, while looking at my tableview, I can add a new item to the database but won't see the change on my tableview until i reload that view again.
var markets: [loadMyData] = []
var marketSelectedText = ""
var myKey = [Any]()
override func viewDidLoad() {
super.viewDidLoad()
ref.child("Markets").observeSingleEvent(of: .value, with: { (snapshot) in
guard snapshot.exists() else
{
print("Null Markets")
return
}
let allMarkets = (snapshot.value as! NSMutableDictionary).allKeys
self.myKey = allMarkets
self.tableView.reloadData()
print(self.myKey, " This is the printing of my key")
})
ref.child("Markets").observe(.value, with: { snapshot in
print(snapshot.value as Any, " ref.observe")
self.tableView.reloadData()
})
}

Right now you're using:
ref.child("Markets").observeSingleEvent(of: .value,
This observes the current data under Markets and then stops observing.
If you want to get both the current data and any changes, use observe(DataEventType.value.

Firebase is providing listeners to observe database changes, kindly check the firebase documentation https://firebase.google.com/docs/database/ios/lists-of-data
FIRDataEventTypeChildChanged
this is the event for listening database changes
commentsRef.observe(.childChanged , with: { (snapshot) in
// here you will get the changed node value here in snapshot.value
})

Related

What is the equivalent of "DatabaseHandle" in firestore?

I am converting the Firebase Realtime database functions to Firestore Database, I am not able to get the equivalent for "DatabaseHandle" as in the below code to configure the database, I need to convert the database for the chat application , this is the tutorial I have been following tutorial reference!
fileprivate var _refHandle: DatabaseHandle?
deinit {
if let refHandle = _refHandle {
self.ref.child("messages").removeObserver(withHandle: refHandle)
}
}
func configureDatabase() {
//ref = Firestore.firestore() // Listen for new messages in the Firebase database
_refHandle = self.ref.collection("messages").observe(.childAdded, with: { [weak self] (snapshot) -> Void in
guard let strongSelf = self else { return }
strongSelf.messages.append(snapshot)
strongSelf.clientTable.insertRows(at: [IndexPath(row: strongSelf.messages.count-1, section: 0)], with: .automatic)
})
}
There is lot of differences in both the database but you can find most of the similarities. Like DatabaseHandle is equivalent to "CollectionReference" and observer's are equivalent to "Listeners".
Rather than following any code, you must refer to official documentation which has a snippet for all features and then you will able to make the difference.
Doc: https://firebase.google.com/docs/firestore
Let me know if you need any more clarification.

Get trouble of updating tableview rows when deleting Firebase data

something goes wrong when trying to update rows of tableview after delete of Firebase data.
Below is method I use.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
let cell = self.messages[indexPath.row]
let b = cell.msgNo
let action = MyGlobalVariables.refMessages.child(MyGlobalVariables.uidUser!)
action.queryOrdered(byChild: "msgNo").queryEqual(toValue: b).observe(.childAdded, with: { snapshot in
if snapshot.exists() { let a = snapshot.value as? [String: AnyObject]
let autoId = a?["autoID"]
action.child(autoId as! String).removeValue()
self.messages.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
} else {
print("snapshot empty")
}}) }
...
return [delete, edit, preview]
}
Initially I checked whole logic without including line /*action.child(autoId as! String).removeValue()*/ then it works normally and removes rows as should be. But once I add this line it removes data from Firebase but tableview is updated in strange way by adding new rows below existing
My guess is that somewhere else in your application you have code like action .observe(.value, which shows the data in the table view. When you delete a node from the database, the code that populates the database gets triggered again, and it adds the same data (minus the node that you removed) to the table view again.
When working with Firebase it's best to follow the command query responsibility segregation principle, meaning that you keep the code that modifies the data completely separate from the flow that displays the data. That means that your code that deletes the data, should not try to update the table view. So something more like:
let action = MyGlobalVariables.refMessages.child(MyGlobalVariables.uidUser!)
action.queryOrdered(byChild: "msgNo").queryEqual(toValue: b).observe(.childAdded, with: { snapshot in
if snapshot.exists() { let a = snapshot.value as? [String: AnyObject]
let autoId = a?["autoID"]
action.child(autoId as! String).removeValue()
} else {
print("snapshot empty")
}}) }
All the above does is remove the selected message from the database.
Now you can focus on your observer, and ensuring it only shows the messages once. There are two options for this:
Always clear self.messages when your .value completion handler gets called before you add the messages from the database. This is by far the simplest method, but may cause some flicker if you're showing a lot of data.
Listen to the more granular messages like .childAdded and .childRemoved and update self.messages based on those. This is more work in your code, but will result in a smoother UI when there are many messages.

Firebase getting specific parent not all children SWIFT

This is my first question here on stackoverflow, but I can't figure this out for the life of me. I am using Xcode and Swift 4.
I want to read a certain child level from Firebase to make a tableView based on the results there. Below is my Firebase data:
I want to make a tableView that lists Bill and Josh which is under "subNames" I seem to only make a snapshot that includes all of Bill and Josh's children as well. I just want the list of items directly in the subNames child. Anybody know how to do this? I am sure I am missing something..
This is my code:
var ref: DatabaseReference!
var refHandle: UInt!
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
}
func loadmoreData () {
refHandle = ref?.child("Users").child(FBuid).observe(.value, with : { (snapshot) in
let mynamesArray = snapshot.childSnapshot(forPath: "subNames")
print (mynamesArray)
})
To get an array with just the keys under subNames, you'll need something like this:
refHandle = ref?.child("Users").child(FBuid).child("subNames").observe(.value, with : { (snapshot) in
let mynamesArray = [String]()
for child in snapshot.children {
mynamesArray.append(child.key)
}
print (mynamesArray)
})

Firebase ChildAdded Observer is Retrieving Data That Doesn't Exist

I am using a child added observer to check if a user gets a new notification while using my app...
func newLikeNotificationObserver() {
notifHandle = Database.database().reference().child("notifications").child(FirebaseDatabase.system.CURRENT_USER_ID).observe(DataEventType.childAdded, with: { (snapshot) in
if !snapshot.exists() {
print("ERROR")
return
}
let id = snapshot.key
print(id)
if let dict = snapshot.value as? Dictionary<String, Any> {
print("ADDED TO LIST")
let notif = Notifications(notifID: id, data: dict)
self.notifications.insert(notif, at: 0)
self.collectionView.reloadData()
}
})
}
The strange issue that I am having is that despite no data being written to my database for when a user likes his/her own posts, the observer is triggered and a Notification is inserted to the array containing the actual user notifications. When I print out the notif-ID to see if I can find it in my DB, its no-where to be found. Can anybody see were I may have gone wrong?
Also, I am removing the observer in the deinit method and adding it in viewdidload(). Thanks in advance
The correct place to put event observers is in viewDidAppear and remove them in viewWillDisappear.
I think its likely that a previous observer is not being removed and is returning bad data. restart the computer and see if it occurs on the initial running of the app, or only on subsequent launches

TableView.reloadData() doesn't work after save data into core data entity

I'm trying to insert a default record into my core data entity while the tableview first-time loaded and checked there's no data in the entity.
The data inserted just fine , but the reloadData() didn't work, after navigate to other view and navigate back to the view the data appears. no matter the reloadData() in or out of the .save() method.
override func viewDidLoad() {
let cateContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let categoryRequest = NSFetchRequest(entityName: "Category")
categoryArray = (try! cateContext.executeFetchRequest(categoryRequest)) as! [Category]
if categoryArray.count == 0 {
let category = NSEntityDescription.insertNewObjectForEntityForName("Category", inManagedObjectContext: cateContext) as! Category
category.sno = "1"
category.category = "General"
category.locate = false
do {
try cateContext.save()
self.categoryTableView.reloadData()
} catch let saveError as NSError {
print("Saving Error : \(saveError.localizedDescription)")
}
}
//self.categoryTableView.reloadData()
}
If your are calling self.categoryTableView.reloadData() in viewDidLoad() method it will not reload your tableView twice. You need to call self.categoryTableView.reloadData() after you have checked if entity existed again.