Delete Post from Firebase Database - ios

Post Structure
retrieving the data
I'm trying to delete posts from the Firebase Database. I'm having a ruff time removing values that are generated from an AutoID.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete{
let user = FIRAuth.auth()?.currentUser
let uid = user?.uid
ref?.child("tests").child(uid!)/* The Posts AutoID*/.removeValue()
tableView.reloadData()
}
}

You'll need to retrieve the post IDs when the data is being fetched. For example, when fetching data just grab the post ID as well.
ref.child("tests").child(uid!).observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let childSnap = child as! FIRDataSnapshot
print(childSnap.key) // SAVE THIS KEY SOMEWHERE, USE IT TO DELETE
}
)}

Related

tableview commit editingStyle is removing the wrong entry

The following code is deleting the wrong entry. I have an array that shows a list of events. in the debugger indexPath.row shows 1 (which is the entry I selected to delete. However when the view refreshes it has deleted the entry 4.
func tableView(_ tableView: UITableView,
commit editingStyle: UITableViewCellEditingStyle,
forRowAt indexPath: IndexPath) {
print(type(of: selectedRecipient))
var eventsOnArray = selectedRecipient?.events?.allObjects
guard let event = eventsOnArray?[indexPath.row] as? Event, editingStyle == .delete else {
return
}
managedContext.delete(event)
do {
try managedContext.save()
print("Deleted")
eventsOnArray?.remove(at: indexPath.row)
getEvents()
self.eventList.reloadData()
} catch let error as NSError {
print("Saving error: \(error), description: \(error.userInfo)")
}
}
My guess here is that the order of your data source is not the same as the array you use in the code we see.
I base this on the fact that you call events?.allObjects which suggests that events is a NSSet which is unordered and calling allObjects on it gives you an array with an undefined order. You need to have an array instead of a set so you can guarantee the same sort order of your objects through different parts of your code.
Adding to #Joakim Danielson’s answer, you would add an extension for your entity to provide for an array instead of a set, like this:
extension Recipient {
var eventsArray: [Event] {
get {
if let eventSet = events as? Set<Event> {
return eventSet.sorted { (item0, item1) -> Bool in
return item0.title < item1.title
}
}
return []
}
}
}
This assumes there is a title attribute in your Event entity so the array returns all events sorted by title. Modify the sorted closure according to your needs.

Synchronize database of Firebase with Swift 4 language

I am new at swift 4 programming. I try to show some data(actually they are child names) from database of firebase. When view did load, I can take them and show on tableView but it is not working real time. When I delete some data from firebase, I need to refresh(go back and load again) the viewController. If I refresh the tableView with timer, all data append from its end. If I, firstly, delete after append new data to tableView. It is jittering. Is there anyway to synchronize this tableView with firebase, without these problems?
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
ref.keepSynced(true)
let userRef = self.ref.child("Users").child(Username).child("Schedule")
userRef.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
self.myList.append(key)
self.CourseList.append(key)
self.LessonsTableView.reloadData()
}
// Lessons are taking and after, they are locating under phone's memory!
UserDefaults.standard.set(self.CourseList, forKey: "LessonsArray")
UserDefaults.standard.synchronize()
})
}
//Setting up our table
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = LessonsTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! LessonsTableViewCell
cell.myLabell.text = myList[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let Dummy:String = myList[indexPath.row] as Any as! String
let Selected:String = (Dummy as NSString) as Any as! String
UserDefaults.standard.set(Selected, forKey: "Selected")
self.performSegue(withIdentifier: "NextPage", sender: self)
}
Firebase's task is a network task which normally runs on a background (lower priority) thread. But tableView.reloadData() is an UI task. So you probably need to execute UI related codes by following codes.
DispatchQueue.main.sync {
let snap = child as! DataSnapshot
let key = snap.key
self.myList.append(key)
self.CourseList.append(key)
self.LessonsTableView.reloadData()
}
it is giving an error like this,
let userRef = self.ref.child("Users").child(Username).child("Schedule")
userRef.observeSingleEvent(of: .value, with: { snapshot in
DispatchQueue.main.sync {
let snap = child as! DataSnapshot
let key = snap.key
self.myList.append(key)
self.CourseList.append(key)
self.LessonsTableView.reloadData()
}
UserDefaults.standard.set(self.CourseList, forKey: "LessonsArray")
UserDefaults.standard.synchronize()
})

Firebase: delete item from row (Swift 3)

I have a tableview showing data from a Firebase console (JASON structure) like this:
chklst-xxx
- avaliation
-students
-KHZAjBi44eZ8JsaswkKI
-teacher: Paul
-datTime: 09.12.2016 12:25pm
-name: Mary Anne
-mark: 7.5
-preceptor: John
-KHWZlh7aasy78ahsiuKIi0
-teacher: Paul
-datTime: 09.12.2016 12:48pm
-name: Anne Caroline
-mark: 9.4
-preceptor: Peter
These data are shown at a tableview, each one, after node students, except the key. I have one function to delete an especific row, as i do with other apps in CoreData (tableview editingStyle):
// FUNC DELETAR
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
teste.remove(at: indexPath.row)
ref.removeValue() // HERE IS MY DOUBT
tableView.reloadData()
}
}
I can erase the item from the array and from the table, but i just don't know how to do it from Firebase. I have tried other ways with removeValue, but it just didn't work, except an way to erase the whole data, not specifically that row selected.
let ref = FIRDatabase.database().reference().child("avaliation").child("students")
I need some teaching to make this works. Thank you.
Here is my method for Saving this data: (Added 09.12 19:30pm)
func Save(){
let ref = FIRDatabase.database().reference().child("avaliation").child("students").childByAutoId()
referencia.child(“name”).setValue(Name)
referencia.child(“teacher”).setValue(Teacher)
referencia.child("preceptor").setValue(Preceptor)
referencia.child("datTime”).setValue(DateTime)
referencia.child(“mark”).setValue(ResultComFReFC)
}
And here is my Class where I work with the main Array:
import Foundation
import Firebase
struct ChkList {
var name: String?
var teacher: String?
var preceptor: String?
var DateToday: String?
var mark: String?
var key: String!
init(name: String, teacher: String, preceptor: String, mark: String, DateToday: String, key: String = "") {
self.name = name
self.teacher = teacher
self.preceptor = preceptor
self.mark = mark
self.DateToday = DateToday
self.key = key
}
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
let snapshotValue = snapshot.value as! [String: AnyObject]
name = snapshotValue["name"] as? String
teacher = snapshotValue["teacher"] as? String
preceptor = snapshotValue["preceptor"] as? String
mark = snapshotValue["mark"] as? String
DateToday = snapshotValue["DateToday"] as? String
}
func toAnyObject() -> Any {
return [
"name": name,
"teacher": teacher,
"preceptor": preceptor,
"mark": mark,
"DateToday": DateToday ]}}
UPDATE: Tableview EdityingStyle
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let ref = FIRDatabase.database().reference().child("avaliation").child("students").childByAutoId()
teste.remove(at: indexPath.row) //Array delet item
let userKeyA = ref.key
ref.child(userKeyA).removeValue()
tableView.reloadData()
}
}
My suggestion, store the pushKey of the user by using 'getKey' method when you push the user details.
chklst-xxx
- avaliation
-students
-KHZAjBi44eZ8JsaswkKI
-teacher: Paul
-userKey:KHZAjBi44eZ8JsaswkKI <--------------
-datTime: 09.12.2016 12:25pm
-name: Mary Anne
-mark: 7.5
-preceptor: John
Now you can retrieve the 'key` of the user. Suppose you are listing, users in the list view and would want to delete a row.
let ref = FIRDatabase.database().reference().child("avaliation").child("students").child(students.getUserKey()).removeValue();
Let me know, if it works.
Update: I don't know swift. But i'll give u an abstract idea.
When you create a new student, you refer student node and push() right. Like below,
DatabaseReference studentsRef = FIRDatabase.database().reference().child("avaliation").child("students").push();
And then you put your data like,
studentRef.child("teacher").setValue("Paul");
studentRef.child("userKey").setValue(studentRef.getKey()); <------------
I did it, using suggests above and studying and trying a lot.
The way to the method works is really capture the userkey.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let user: ChkList = teste[indexPath.row]
let uk = user.key
print("Userkey: \(uk)")
ref.child(uk!).removeValue()
}
}
This way you will have removed the data from Firebase and the row form tableview.
This answer moves the Firebase delete behavior behind the scenes so as
to not interfere with the normal tableview loading mechanisms. One
benefit is reducing the number of calls to Firebase and removing
timing issues from the internal tableview animation process.
What worked for me is getting the Firebase stuff out of the way. In my case, I collect all the keys that I want. During the delete, I remove the values from my local object, and when leaving the scene I call my cleanup method from viewDidDisappear() to sync the updated data back to Firebase:
func syncFavorites() {
//ref is the leaf for the favorites
//clear existing
ref?.removeValue()
//temp collection
var faves = [String:Any]()
//dataArrayKeys is my collection of keys on self
dataArrayKeys.keys.forEach { (key) in
faves.updateValue("true", forKey: key)
}
ref?.updateChildValues(faves)
}
I handle my tableview's delete action using the normal method.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
if let key = dataArr[indexPath.row]["key"] as? String {
dataArrayKeys.removeValue(forKey: keyToDelete)
dataArr.remove(at: indexPath.row)
}
tableView.deleteRows(at: [indexPath], with: .fade)
self.tableView.reloadData()
}
}
I have no doubt there is probably a better way. This was the simplest possible thing that worked for me.

How can I delete a specific child node in Firebase from UITableViewCell using Swift

I have a UITableView which looks like this image
.
When I swipe to delete the record, I can remove it perfectly okay from the array in which it is stored, but I am having difficulties in accessing it in Firebase to delete it there.
My Firebase database structure is as follows for the above screenshot:
-KWc7RTuOe5PefiMM2tL
bodyPart: "Arms"
exerciseName: "Test 1 "
userId: "8rHmyTxdocTEvk1ERiiavjMUYyD3"
-KWcEbpw_f6kxcePY5cO
bodyPart: "Chest"
exerciseName: "Test 2 "
userId: "8rHmyTxdocTEvk1ERiiavjMUYyD3"
-KWcEdUN49QaJIVf0kwO
bodyPart: "Legs"
exerciseName: "Test 3 "
userId: "8rHmyTxdocTEvk1ERiiavjMUYyD3"
-KWcFrMSaLKQRxghGHyT
bodyPart: "Arms"
exerciseName: "Test 4"
userId: "8rHmyTxdocTEvk1ERiiavjMUYyD3"
How can I access the autoId value which is set when it is created e.g "-KWc7RTuOe5PefiMM2tL" so I can remove that child node?
Or alternatively could I access the exerciseName value depending on the UserId that is logged in?
To solve this issue I tried a number of different methods before finally reaching my intended result.
To delete the value, I created a reference to the child node 'userExercises', then ordered it by 'exerciseName' and then .queryEqual(toValue:) the exercise name value which I extracted form the UITableViewCell.
I then removed the snapshot value of this and the example code is below:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
if let exerciseName = exercises[indexPath.row].exerciseName {
let ref = FIRDatabase.database().reference().child("userExercises")
ref.queryOrdered(byChild: "exerciseName").queryEqual(toValue: exerciseName).observe(.childAdded, with: { (snapshot) in
snapshot.ref.removeValue(completionBlock: { (error, reference) in
if error != nil {
print("There has been an error:\(error)")
}
})
})
}
exercises.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .left)
}
}
Following on from what MHDev has already answered:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
if let exerciseName = exercises[indexPath.row].exerciseName {
let ref = FIRDatabase.database().reference().child("userExercises")
ref.queryOrdered(byChild: "exerciseName").queryEqual(toValue: exerciseName).observe(.childAdded, with: { (snapshot) in
snapshot.ref.removeValue(completionBlock: { (error, reference) in
if error != nil {
print("There has been an error:\(error)")
}
})
})
}
exercises.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .left)
}
}
It's a fairly straightforward process:
In general, a datasource for tableViews is an array. That array is built from dictionaries read from Firebase snapshots - or an array of objects built from the snapshots (recommended).
So here's an example that matches your Firebase structure (this was populated from a single node from a snapshot)
class Exercise {
key: "KWc7RTuOe5PefiMM2tL"
bodyPart: "Legs"
exerciseName: "Test 3 "
userId: "8rHmyTxdocTEvk1ERiiavjMUYyD3"
}
Then, when the user swipes row 3 for example, retrieve the Exercise object from the array, row3.
let theObject = ExerciseArray[3]
let parentNode = theObject.key
let ref = rootNode.child(parentNode)
ref.setValue(nil)
and you're done.

Deleting certain objects in background from UITableViewCell With Swift and Parse

So I have a UITableViewCell and I want to delete the image from the tableView. But I also want to delete the given object from the Parse database.
I have the image object saved in the online Parse framework and in the Local Datastore.
for i in images{
var imageNames = i.thumbnailImage
var imageFile = PFFile(data: UIImagePNGRepresentation(imageNames))
//Pin the objects here!!
var imageObject = PFObject(className: "img")
imageObject["theImg"] = imageFile
//imageObject["user"] = PFUser.currentUser()?.username
imageObject.pinInBackgroundWithName("imgs")
var objID = imageObject.objectId
imageObject.pinInBackgroundWithBlock({ (success, error) -> Void in
if error == nil{
println("Object Saved!!")
imageObject.save()
println(objID)
self.imagesFromParse.append(imageNames!)
self.tableView.reloadData()
} else {
println(error)
}
})
I then have the delete UITableViewCell function called here -
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
var cell:nudeCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! nudeCell
if editingStyle == UITableViewCellEditingStyle.Delete{
if self.imagesFromParse.count >= 1{
self.imagesFromParse.removeAtIndex(indexPath.row)
//Here is where i want to delete the object from the localDatastore and the online framwork
}
}
}
The problem is that when I try to delete the object in the background. I do not know how to get the specific object ID in the given indexPath to delete.

Resources