【问题标题】:How do I overwrite an identifiable object by refrencing it with an ID in swiftui?如何通过在 swiftui 中使用 ID 引用它来覆盖可识别的对象?
【发布时间】:2021-08-06 05:54:11
【问题描述】:

我已经简化了我的代码,以便更容易看到我正在尝试做什么,我正在构建一个评分源,这些评分来自我“关注”的任何人的 firebase 文档

我想做的就是每当 firebase 说我的一条评论有新更新时,更改 Identifiable,而不是重新加载我关注的每个人的每条评论。

这是我的观点:

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 比较陌生,所以我可能完全不知道我是如何做到这一点的。非常感谢任何帮助!

【问题讨论】:

  • 将 ObservableObject 和 @Published 添加到 Rating 及其属性。这样,当 Rating 更新其已发布属性之一时,视图将自动重绘。
  • @Helperbug 感谢您的快速回复!我不认为我完全理解你的建议。您是否建议我将“struct Rating: Identifiable”移动到我的 FeedViewModel Observable 对象类中?如果是这样,我将如何覆盖我的 allRatings 数组中的评分之一?
  • Rating 必须是具有已发布属性的可观察值。当评级的属性更新时,它将发布更改,并且视图将知道自己更新。尝试将评级等级更改为:class Rating: ObservableObject, Identifiable { var id: String @Published var review: String Published var likes: Int }
  • 当我真的觉得这会奏效哈哈遗憾的是我收到以下错误:“参数传递给不带参数的调用删除'(id:id,review:review,likes:likes )'" 每当我尝试运行任何尝试写入/推送到可识别评级的函数时。

标签: swift firebase google-cloud-firestore swiftui identifiable


【解决方案1】:

经过一周的尝试,我终于明白了,希望这对某人有所帮助,如果您想覆盖数组中的可识别项,请使用您的 id 查找索引。在我的例子中,我的 ID 是 firebaseCollectionID + firebaseDocumentID,所以这使它始终 100% 唯一并且它允许我从快照侦听器中引用它...

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

然后通过以下方式覆盖它:

self.allRatings[index!] = Rating(id: id, review: review, likes: likes)

【讨论】:

    猜你喜欢
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-28
    • 2015-11-12
    • 2017-11-06
    • 1970-01-01
    相关资源
    最近更新 更多