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
我有一个名为 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