我可以提供三个不同的版本。
所有这些都切换单个按钮并保持整个模型 - ColorStore var 同步。允许添加和删除颜色数组中的元素。另请注意,我们可以不使用 Identifiable 一致性来列出数组元素。
版本1.最接近问题:所有型号都是classes。
class CustomColor: ObservableObject, Identifiable {
var didChange = PassthroughSubject<CustomColor, Never>()
let id = UUID()
var color: Color {
didSet {
objectWillChange.send()
}
}
init(color: Color) {
self.color = color
}
func change(to color: Color) {
self.color = color
}
}
class ColorStore: ObservableObject {
var didChange = PassthroughSubject<ColorStore, Never>()
var colors: [CustomColor] = [] {
didSet {
objectWillChange.send()
}
}
init() {
(0...10).forEach { _ in colors.append(CustomColor(color: .red)) }
}
}
struct ContentView: View {
@ObservedObject var colorStore: ColorStore = ColorStore()
var body: some View {
NavigationView {
List(colorStore.colors) { c in
ColorShape(color: c)
}
// will work without `Identifiable`
// List(colorStore.colors.indices, id: \.self) { c in
// ColorShape(color: self.colorStore.colors[c])
// }
.navigationBarTitle(Text("Colors"))
.navigationBarItems(leading:
Button(action: { self.colorStore.colors.append(CustomColor(color: .green)) }) {
Text("Add")
}, trailing:
Button(action: {
self.colorStore.colors.removeLast()
print(self.colorStore.colors)
}, label: { Text("Remove") }))
}
}
}
struct ColorShape: View {
@ObservedObject var color: CustomColor
var body: some View {
Button(action:
{ self.color.change(to: .blue)
print(self.color)
}
, label: {
Circle().fill(color.color)
})
}
}
版本 2。CustomColor 被重写为结构。
// No need for manual `ObservableObject, Identifiable` conformance
struct CustomColor /*: Identifiable */ {
// let id = UUID()
var color: Color
init(color: Color) {
self.color = color
}
mutating func change(to color: Color) {
self.color = color
}
}
class ColorStore: ObservableObject {
var didChange = PassthroughSubject<ColorStore, Never>()
// If `CustomColor` is a `struct` i.e. value type, we can populate array with independent values, not with the same reference by using `repeating:` init.
var colors: [CustomColor] = Array(repeating: CustomColor(color: .red), count: 10) {
didSet {
objectWillChange.send()
}
}
/* init() {
(0...10).forEach { _ in colors.append(CustomColor(color: .red)) }
} */
}
struct ContentView: View {
@ObservedObject var colorStore: ColorStore = ColorStore()
var body: some View {
NavigationView {
List {
// Strange, bu if we omit ForEach, we will get an error on element removal from array.
ForEach(colorStore.colors.indices, id: \.self)
{ c in
ColorShape(color: self.$colorStore.colors[c])
}
}
.navigationBarTitle(Text("Colors"))
.navigationBarItems(leading:
Button(action: { self.colorStore.colors.append(CustomColor(color: .green)) }) {
Text("Add")
}, trailing:
Button(action: {
self.colorStore.colors.removeLast()
print(self.colorStore.colors)
}, label: { Text("Remove") }))
}
}
}
struct ColorShape: View {
@Binding var color: CustomColor
var body: some View {
Button(action:
{ self.color.change(to: .blue)
print(self.color)
}
, label: {
Circle().fill(color.color)
})
}
}
版本 3. 主模型 ColorStore 及其子类型 CustomColor 被重写为结构。无需手动符合ObservableObject。
struct CustomColor /* : Identifiable */ {
// let id = UUID()
var color: Color
init(color: Color) {
self.color = color
}
mutating func change(to color: Color) {
self.color = color
}
}
struct ColorStore {
// If `CustomColor` is a `struct` i.e. value type, we can populate array with independent values, not with the same reference by using `repeating:` init.
var colors: [CustomColor] = Array(repeating: CustomColor(color: .red), count: 10)
}
struct ContentView: View {
@State var colorStore: ColorStore = ColorStore()
var body: some View {
NavigationView {
List{
ForEach(colorStore.colors.indices, id: \.self) { i in
return ColorShape(color: self.$colorStore.colors[i])
}
}
.navigationBarTitle(Text("Colors"))
.navigationBarItems(leading:
Button(action: { self.colorStore.colors.append(CustomColor(color: .green)) }) {
Text("Add")
}, trailing:
// Removing causes index out of bound error (bug?)
Button(action: {
self.colorStore.colors.removeLast()
print(self.colorStore.colors)}) {
Text("Remove") })
}
}
}
struct ColorShape: View {
@Binding var color: CustomColor
var body: some View {
Button(action: {
self.color.change(to: .blue)
print(self.color)
}) {
Circle().fill(color.color)
}
}
}