Как мне перезаписать идентифицируемый объект, заменив его идентификатором в swiftui?

Я упростил свой код, чтобы было легче увидеть, что я пытаюсь сделать, я создаю ленту оценок, которые получены из документов firebase тех, за кем я "подписан".

Все, что я хочу сделать, - это всякий раз, когда firebase сообщает о новом обновлении одного из моих обзоров, изменить его, а не перезагружать каждый отзыв от каждого человека, за которым я подписан.

Вот мой взгляд:

      import SwiftUI
import Firebase

struct Rating: Identifiable {
    var id: String
    var review: String
    var likes: Int
}

struct Home: View {
    
    @ObservedObject var feedViewModel = FeedViewModel()

    var body: some View {
        VStack{
                         
           ForEach(self.feedViewModel.allRatings, id: \.id){ rating in
               Text(rating.review)
               Text("\(rating.likes)")
           }
        }
     }
}

Вот мои функции для FeedViewModel:

      class FeedViewModel: ObservableObject {

     @Published var following = ["qedXpEcaRLhIa6zWjfJC", "1nDyDT4bIa7LBEaYGjHG", "4c9ZSPTQm2zZqztNlVUp", "YlvnziMdW8VfibEyCUws"]
     @Published var allRatings = [Rating]()

     init() {
         for doc in following {
              
              // For each person (aka doc) I am following we need to load all of it's ratings and connect the listeners
              getRatings(doc: doc)
              initializeListener(doc: doc)

          }
      }


    func getRatings(doc: String) {
        
        db.collection("ratings").document(doc).collection("public").getDocuments() { (querySnapshot, err) in
            
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                
 
                // We have to use += because we are loading lots of different documents into the allRatings array, allRatings turns into our feed of reviews.
                self.allRatings += querySnapshot!.documents.map { queryDocumentSnapshot -> Rating in
                   let data = queryDocumentSnapshot.data()
                   let id = ("\(doc)-\(queryDocumentSnapshot.documentID)")
                   let review = data["review"] as? String ?? ""
                   let likes = data["likes"] as? Int ?? 0

                   return Rating(id: id, review: review, likes: likes)

                }
            }
      }


    func initializeListener(doc: String){
        
        db.collection("ratings").document(doc).collection("public")
            .addSnapshotListener { (querySnapshot, error) in
            
            guard let snapshot = querySnapshot else {
                print("Error listening for channel updates")
                return
            }

            snapshot.documentChanges.forEach { change in

                for document in snapshot.documents{

                   let data = document.data()
                   let id = ("\(doc)-\(document.documentID)")
                   let review = data["review"] as? String ?? ""
                   let likes = data["likes"] as? Int ?? 0

                   // I thought swiftui Identifiables would be smart enough to not add another identifiable if there is already an existing one with the same id, but I was wrong, this just duplicates the rating
                   // self.allRatings.append(Rating(id: id, review: review, likes: likes))

                   // This is my current solution, to overwrite the Rating in the allRatings array, however I can not figure out how to get the index of the changed rating
                   // "0" should be replaced with whatever Rating index is being changed
                   self.allRatings[0] = Rating(id: id, review: review, likes: likes)

                }
            }
        }
     }

}

Все, что я хочу, - это сделать так, чтобы "лайки" каждого рейтинга постоянно обновлялись, когда кому-то нравится рейтинг. Это кажется простым, но я относительно новичок в swiftui, поэтому я могу совершенно не понимать, как я это делаю. Любая помощь приветствуется!

1 ответ

Решение

После недели попыток понять это я наконец понял, надеюсь, это поможет кому-то, если вы хотите перезаписать идентифицируемый в своем массиве, найдите индекс, используя свой идентификатор. В моем случае мой идентификатор - это firebaseCollectionID + firebaseDocumentID, поэтому он всегда на 100% уникален и позволяет мне ссылаться на него из прослушивателя снимков ...

      let index = self.allRatings.firstIndex { (Rating) -> Bool in
    Rating.id == id
}

Затем перезапишите его, выполнив:

      self.allRatings[index!] = Rating(id: id, review: review, likes: likes)
Другие вопросы по тегам