Swift 结构错误(不能在不可变值上使用可变成员:'self' 是不可变的)使用 Firebase

Swift struct error (Cannot use mutating member on immutable value: 'self' is immutable) using Firebase

我有一个名为 myObjectHolder 的自定义 struct,它有一个名为 myArray 的自定义 struct(称为 myObject)数组。

我尝试获取存储在 Firebase-Firesrtore 中的数据并将其附加到数组(使用将 Firebase 文档转换为 myObject 的函数)。

我试着这样做:

struct myObjectHolder {
    var myArray = [myObject]()


    private func fetchMyObjects() {
        let db = Firestore.firestore().collection("myObjects").getDocuments { (querySnapshot, err) in
        for document in querySnapshot!.documents {
            self.myArray.append(self.myObjectFromDocument(document: document)) //Error
        }
    }
}

出于某种原因,当我尝试将新的 myObject 附加到 myArray 时,我收到此错误消息:

Cannot use mutating member on immutable value: 'self' is immutable

有人知道我该如何解决吗? (我正在使用 SwiftUI 这很重要)

谢谢!

使用 class 而不是 struct 是一种解决方案 - 如果您认为 struct 适合您的设计,那么使用

struct myObjectHolder {
    var myArray = [myObject]()


    private mutating func fetchMyObjects() {
        let db = Firestore.firestore().collection("myObjects").getDocuments { (querySnapshot, err) in
        for document in querySnapshot!.documents {
            self.myArray.append(self.myObjectFromDocument(document: document)) //Error
        }
    }
}

我刚刚将它从 struct 更改为 class,并且效果很好。

之前其他人所说的是正确的:您不能修改结构,因此您应该使用 class - 或者使结构可修改。有关详细信息,请查看 https://chris.eidhof.nl/post/structs-and-mutation-in-swift/

既然你特别提到了 Firestore,我建议你使用 MVVM 架构:

将您的数据访问逻辑放入视图模型中:

import Foundation
import FirebaseFirestore
import FirebaseFirestoreSwift

class ThingViewModel: ObservableObject {
  @Published var things = [Thing]()

  private var db = Firestore.firestore()

  func fetchData() {
    db.collection("things").addSnapshotListener { (querySnapshot, error) in
      guard let documents = querySnapshot?.documents else {
        print("No documents")
        return
      }

      self.things = documents.map { queryDocumentSnapshot -> Thing in
        return queryDocumentSnapshot.data(as: Thing.self)
      }
    }
  }
}

在你的视图中,实例化视图模型并观察发布的things数组:

struct ThingsListView: View {
  @ObservedObject var viewModel = ThingsViewModel()

  var body: some View {
    NavigationView {
      List(viewModel.things) { thing in
        VStack(alignment: .leading) {
          Text(thing.name)
            .font(.headline)
        }
      }
      .navigationBarTitle("Things")
      .onAppear() {
        self.viewModel.fetchData()
      }
    }
  }
}

此外,对 Swift 结构和 classes 使用 UpperCamelCase 是一种很好的做法:https://github.com/raywenderlich/swift-style-guide#naming