I'm trying to delete an object from my Firestore database through SwiftUI and the data deletes successfully. However it doesn't update in my UI, unless I reload it manually.
Right now, I'm using @Environment(\.presentationMode) var presentation
to dismiss the view after deletion completion.
Here's my Firebase code:
func deleteData(category: String,completion: @escaping (success) -> Void){
db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").getDocument{(snapshot, error) in
guard let snapshot = snapshot, error == nil else {
return
}
let documentID = snapshot.data()!["date"] as! String
db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID).document("\(category)").delete(){ err in
if let err = err {
print("Error removing document: \(err)")
completion(false)
} else {
print("Document successfully removed!")
completion(true)
}
}
}
}
And here's the SwiftUI code:
@Environment(\.presentationMode) var presentation
var body: some View {
ForEach(self.data){item in
HStack{
Text(item.category)
Spacer()
Button(action: {
deleteData(category: item.category!){
(success) -> Void in
if success {
print("deleted successfully")
self.presentation.wrappedValue.dismiss()
}
}
}){
Text("Delete")
}
}
.onAppear{
fetchData()
}
}
}
class FirebaseData: ObservableObject {
@State var id: String?
@State var category: String
@State var password: String
init(id: String?, password: String, category: String) {
self.id = id
self.password = password
self.category = category
}
}
self.data
comes from @State var data: [FirebaseData] = []
.
There are a few problems here:
In general, when doing asynchronous work, you probably want to do them in an ObservableObject
, and not in the View
itself -- I've moved the code into a view model.
Your model shouldn't be an ObservableObject
-- it should just be a struct. Using @State
on an ObservableObject
doesn't do anything anyways -- use @Published
values when using ObservableObject
You're using getDocument
which gets the data once , which is why your UI isn't updating. If you want the UI to update, use snapshot listeners: https://firebase.google.com/docs/firestore/query-data/listen
struct FirebaseData {
var id: String?
var category: String
var password: String
}
class ViewModel : ObservableObject {
@Published var data : [FirebaseData] = []
private let db = Firestore.firestore()
private var listener : ListenerRegistration?
func fetchData(){
db.collection("passwords").document("\(Auth.auth().currentUser!.uid)")
.getDocument{(snapshot, error) in
guard let snapshot = snapshot, error == nil else {
return
}
let documentID = snapshot.data()!["date"] as! String
self.listener = self.db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID)
.addSnapshotListener(){ (querySnapshot, err) in //<-- Here
if let err = err {
print("Error getting documents: \(err)")
} else {
self.data = (querySnapshot?.documents ?? []).map {
FirebaseData(id: $0.documentID,
category: $0.data()["category"] as? String ?? "",
password: $0.data()["password"] as? String ?? "")
}
}
}
}
}
func deleteData(category: String,completion: @escaping (success) -> Void){
db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").getDocument{(snapshot, error) in
guard let snapshot = snapshot, error == nil else {
return
}
let documentID = snapshot.data()!["date"] as! String
self.db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID).document("\(category)").delete(){ err in
if let err = err {
print("Error removing document: \(err)")
completion(false)
} else {
print("Document successfully removed!")
completion(true)
}
}
}
}
}
struct ContentView: View {
@Environment(\.presentationMode) var presentation
@StateObject private var viewModel = ViewModel()
var body: some View {
NavigationView{
ForEach(viewModel.data, id: \.self.id) { item in
HStack{
Text(item.category)
Spacer()
Button(action: {
viewModel.deleteData(category: item.category){
(success) -> Void in
if success {
print("deleted successfully")
}
}
}){
Text("Delete")
}
}
}
.onAppear{
viewModel.fetchData()
}
}
}
}
There's some more refactoring I'd do, such as:
!
anywhere to force unwrap -- this can cause crashesdeleteData
But, this should get you started for now.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.