Xcode 12。代码和生命周期是Swiftui.
我看过其他人的相关问题,似乎他们只是把他们的整个项目代码倾倒在这里;从中挑选我需要的东西有点难。所以,我把这个问题分解成一个最简单的例子。
目标是让numberX在我按+键时迭代。
提前感谢!
struct InfoData: Identifiable {
var id = UUID()
var nameX: String
var numberX: Int
}
class ContentX: ObservableObject {
@Published var infoX = [
InfoData(nameX: "Example", numberX: 1)
]
}
struct ContentView: View {
@StateObject var contentX = ContentX()
var body: some View {
List(contentX.infoX) { item in
HStack {
Text("(item.nameX)")
Spacer()
Button("+") {
item.numberX += 1 //Eror shows up here <<
}
Text("(item.numberX)")
}
}
}
}
在您使用的语法中,item
是一个不可变的值,正如错误告诉您的那样。你不能改变它,因为它不代表与它来自的数组的真正连接——它只是一个临时可读的副本,在List
迭代中使用。
如果你可以升级到Xcode 13,你可以访问List
和ForEach
中的元素绑定语法,让你这样做:
struct ContentView: View {
@StateObject var contentX = ContentX()
var body: some View {
List($contentX.infoX) { $item in //<-- Here
HStack {
Text("(item.nameX)")
Spacer()
Button("+") {
item.numberX += 1
}
Text("(item.numberX)")
}
}
}
}
这给你一个Binding
item
是可变的,允许你改变它的值(s)和反映在原始数组。
在Xcode 13/Swift 5.5之前,你必须定义自己的方式来改变数组中的元素。这是一个解决方案:
class ContentX: ObservableObject {
@Published var infoX = [
InfoData(nameX: "Example", numberX: 1)
]
func alterItem(item: InfoData) {
self.infoX = self.infoX.map { $0.id == item.id ? item : $0 }
}
}
struct ContentView: View {
@StateObject var contentX = ContentX()
var body: some View {
List(contentX.infoX) { item in
HStack {
Text("(item.nameX)")
Spacer()
Button("+") {
var newItem = item
newItem.numberX += 1
contentX.alterItem(item: newItem)
}
Text("(item.numberX)")
}
}
}
}
或者,使用自定义Binding
的另一个选项:
class ContentX: ObservableObject {
@Published var infoX = [
InfoData(nameX: "Example", numberX: 1)
]
func bindingForItem(item: InfoData) -> Binding<InfoData> {
.init {
self.infoX.first { $0.id == item.id }!
} set: { newValue in
self.infoX = self.infoX.map { $0.id == item.id ? newValue : $0 }
}
}
}
struct ContentView: View {
@StateObject var contentX = ContentX()
var body: some View {
List(contentX.infoX) { item in
HStack {
Text("(item.nameX)")
Spacer()
Button("+") {
contentX.bindingForItem(item: item).wrappedValue.numberX += 1
}
Text("(item.numberX)")
}
}
}
}