从Firestore获取数据并将其正确添加到数组中

3

我正在尝试从Firestore获取数据。我已经有了下面的代码,但是如何正确地将数据添加到shelters中?

当前错误:

类型为“[String : Any]”的值没有成员“title”

class FirebaseSession: ObservableObject {

    @Published var shelters: [Shelter] = []

    let ref = Firestore.firestore().collection("shelters")

    getShelters() {
        ref.getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                for document in querySnapshot!.documents {
                    let value = document.data()
                    let shelter = Shelter(id: Int(value.id), title: value.title, image: value.image, availableSpaces: value.available, distance: value.distance, gender: value.gender)
                    self.$shelters.append(shelter)
                }
            }
        }

    }

}

class Shelter {

    var id: Int
    var title: String
    var image: String
    var availableSpaces: Int
    var distance: Double
    var gender: String?

    init?(id: Int, title: String, image: String, availableSpaces: Int, distance: Double, gender: String?) {

        if id < 0 || title.isEmpty || image.isEmpty || availableSpaces < 0 || distance < 0 {
            return nil
        }

        self.id = id
        self.title = title
        self.image = image
        self.availableSpaces = availableSpaces
        self.distance = distance
        self.gender = gender
    }

}

编辑:

let shelter = Shelter(id: value["id"] as? Int ?? -1, title: value["title"] as? String ?? "", image: value["image"] as? String ?? "", available: value["available"] as? Int ?? -1, distance: value["distance"] as? Double ?? -1, gender: value["gender"] as? String ?? "")
2个回答

2
let shelter = Shelter(id: Int(value.id), title: value.title, image: value.image, availableSpaces: value.available, distance: value.distance, gender: value.gender)

这里value的类型为[String:Any]。所以你不能使用value.title,而需要使用value["title"] as? String ?? "",对于id、image、distance等也是同样的方法。

因此最终代码如下:

let shelter = Shelter(id: Int(value["id"], title: value["title"], image: value["image"], availableSpaces: value["available"], distance: value["distance"], gender: value["gender"])

相应地将其降级。

更新

用以下代码替换您的代码

if let shelter = Shelter(id: value["id"] as? Int ?? -1, title: value["title"] as? String ?? "", image: value["image"] as? String ?? "", available: value["available"] as? Int ?? -1, distance: value["distance"] as? Double ?? -1, gender: value["gender"] as? String ?? "") { 
   self.shelters.append(shelter)
} else { 
   print("provided data is wrong.")
}

我现在对于追加操作出现了以下错误:无法将类型为'Shelter?'的值转换为预期的参数类型'[Shelter]' - Tom
你可以在编辑中找到我的新的 let shelter = .. 代码。 - Tom
@Tim,我已经更新了代码。另外,哪一行产生了上述错误?因为这不应该发生。 - Keshu R.
使用您更新后的代码完成了工作,我只需要使用shelter!Shelter?解包为Shelter - 希望这样可以吗? - Tom
1
@Tim,我已经更新了答案,使用if let语句安全地解包shelter对象。最好使用这个方法,因为如果Shelter初始化失败,它不会使你的应用程序崩溃。 - Keshu R.

0

原始代码存在一些问题:

  1. 你的代码中以下片段创建了一个计算属性,而不是实现获取收容所的函数 - 不确定这是否是你想要的:
getShelters() {
...
}

我建议您使用适当的函数来替换此代码。

  1. 不需要为数据模型使用 class,特别是因为您似乎正在使用 SwiftUI。

  2. 不要手动映射获取的文档(并且必须自己处理 nil 值、类型转换等),我建议使用 Firestore 的 Codable 支持。

我在我的文章 SwiftUI: Mapping Firestore Documents using Swift Codable - Application Architecture for SwiftUI & Firebase | Peter Friese 中详细介绍了这个问题。

以下是应用我的建议后您的代码可能会如何:

struct Shelter: Codable, Identifiable {
  @DocumentID var id: String?
  var title: String
  var image: String
  var availableSpaces: Int
  var distance: Double
  var gender: String?
}


class FirebaseSession: ObservableObject {
  @Published var shelters = [Shelter]()

  private var db = Firestore.firestore()
  private var listenerRegistration: ListenerRegistration?
  
  deinit {
    unsubscribe()
  }
  
  func unsubscribe() {
    if listenerRegistration != nil {
      listenerRegistration?.remove()
      listenerRegistration = nil
    }
  }
  
  func subscribe() {
    if listenerRegistration == nil {
      listenerRegistration = db.collection("shelters").addSnapshotListener { (querySnapshot, error) in
        guard let documents = querySnapshot?.documents else {
          print("No documents")
          return
        }
        
        self.shelters = documents.compactMap { queryDocumentSnapshot in
          try? queryDocumentSnapshot.data(as: Shelter.self)
        }
      }
    }
  }
}

请注意:
  1. 我们可以省略 Shelter 的构造函数。
  2. 当 Firestore 中添加了一个收容所到 shelter 集合中时,shelter 属性将自动更新。
  3. 如果文档不符合预期的数据结构,代码不会崩溃。

我将 Shelter 结构标记为可识别,这样您就可以直接在 List 视图中使用它。 @DocumentID 指示 Firestore 将文档 ID 映射到结构上的相应属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接