KingTim
KingTim

Reputation: 1301

How to delete a child from Firebase (Swift)

I've been following a tutorial on making an instragram-esque app, and I'm having a lot of trouble figuring out how to delete a post, both from Firebase and from the feed. The image that the user selects or takes is uploaded to Firebase database with this function:

func uploadToFirebase() {
    AppDelegate.instance().showActivityIndicator()

    let uid = FIRAuth.auth()!.currentUser!.uid
    let ref = FIRDatabase.database().reference()
    let storage = FIRStorage.storage().reference(forURL: "gs://cloudcamerattt.appspot.com")

    let key = ref.child("posts").childByAutoId().key
    let imageRef = storage.child("posts").child(uid).child("\(key).jpg")

    let data = UIImageJPEGRepresentation(self.previewImage.image!, 0.6)

    let uploadTask = imageRef.put(data!, metadata: nil) { (metadata, error) in

        if error != nil {
            print(error!.localizedDescription)
            AppDelegate.instance().dismissActivityIndicator()
            return
        }

        imageRef.downloadURL(completion: { (url, error) in

            if let url = url {
                // how do I add date: NSDate in here?
                let feed = ["userID" : uid,
                            "pathToImage" : url.absoluteString,
                            "likes" : 0,
                            "author" : FIRAuth.auth()!.currentUser!.displayName!,
                            "postID" : key] as [String : Any]

                let postFeed = ["\(key)" : feed]

                ref.child("posts").updateChildValues(postFeed)
                AppDelegate.instance().dismissActivityIndicator()

                self.dismiss(animated: true, completion: nil)
            }
        })
    }
    uploadTask.resume()
}

Which ends up in Firebase looking like this:

enter image description here

Following a stack overflow answer I found, I tried to set up a delete function to be called when the delete button is pressed. This delete button is on a "photo detail" view, which the user gets to by tapping an image in the image feed - this photo detail view displays the image in a bigger size, along with some other info such as likes:

func deletePost(firstTree: String, childIWantToRemove: String) {

    let uid = FIRAuth.auth()!.currentUser!.uid
    let ref = FIRDatabase.database().reference()
    let storage = FIRStorage.storage().reference(forURL: "gs://cloudcamerattt.appspot.com")

    let key = ref.child("posts").childByAutoId().key
    let imageRef = storage.child("posts").child(uid).child("\(key).jpg")

    ref.child("posts").child(key).child("postID").removeValue { (error, ref) in
        if error != nil {
            print("error \(error)")
        }
    }
}

And call the function here:

@IBAction func moreButtonPressed(_ sender: AnyObject) {

    let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
    let destroyAction = UIAlertAction(title: "Delete", style: .destructive) { action in
        print(action)

        let ref = FIRDatabase.database().reference()
        let key = ref.child("posts").childByAutoId().key

        let firstTree = key
        let valueToRemove = "postID"
        self.deletePost(firstTree: firstTree, childIWantToRemove: valueToRemove)
    }

    alertController.addAction(destroyAction)
    alertController.addAction(cancelAction)
    self.present(alertController, animated: true)
}

I'm not really understanding what I'm doing though, and needless to say tapping the delete button does essentially nothing. Can anyone show me how to fix the delete function so I can remove an image/post from firebase properly?

EDIT: I have var selectedPost: Post! in my PhotoDetailController, which is passed from the FeedViewController (image feed) in didSelectItem like so:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let photoDetailController = self.storyboard?.instantiateViewController(withIdentifier: "photoDetail") as! PhotoDetailController

    photoDetailController.selectedPost = posts[indexPath.row]

    present(photoDetailController, animated: true, completion: nil)
}

So it has the index path. Another note about the above function is that var posts = [Post]() is instantiated in the FeedViewController, so that's where posts[indexPath.row] comes from.

Upvotes: 5

Views: 13217

Answers (2)

Kirill
Kirill

Reputation: 879

According to Firebase docs, you can also delete it by

specifying null as the value for another write operation such as set() or update()

You can use this technique with update() to delete multiple children in a single API call.

Upvotes: 1

user3476154
user3476154

Reputation:

This should work.

func deletePost() {
  let uid = FIRAuth.auth()!.currentUser!.uid
  let storage = FIRStorage.storage().reference(forURL: "gs://cloudcamerattt.appspot.com")

  // Remove the post from the DB
  ref.child("posts").child(selectedPost.postID).removeValue { error in
    if error != nil {
        print("error \(error)")
    }
  }
  // Remove the image from storage
  let imageRef = storage.child("posts").child(uid).child("\(selectedPost.postID).jpg")
  imageRef.delete { error in
    if let error = error {
      // Uh-oh, an error occurred!
    } else {
     // File deleted successfully
    }
  }
}

Also .childByAutoId().key generates a key to insert items into the DB. You can't use it get a reference to an existing item.

Upvotes: 9

Related Questions