预先警告:
这将是
更容易
如果你的模型是一个结构体而不是ObservableObject,你基本上可以免费获得所有这些行为。但是,我假设你的应用程序不能以这种方式构建是有原因的。话虽如此,试图用ObservableObjects阵列做到这一点是一场艰苦的战斗,我认为这是在与SwiftUI的设计工作方式作斗争。然而,这个解决方案似乎确实有效。
import Combine
class MyObservedObject: Hashable, Equatable, ObservableObject {
let id = UUID()
@Published var text: String
init(_ text: String) {
self.text = text
}
static func == (lhs: MyObservedObject, rhs: MyObservedObject) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.id)
}
static func newSet() -> [MyObservedObject] {
return [
MyObservedObject("a"),
MyObservedObject("b"),
MyObservedObject("c"),
]
}
}
class ContainerData: ObservableObject {
@Published var objects = MyObservedObject.newSet()
}
struct Container: View {
@ObservedObject private var data = ContainerData()
var body: some View {
VStack {
ObjectVisualizer(data.objects)
Button("Click me") {
self.data.objects[2].text = "Changed"
data.objectWillChange.send()
}
}
}
}
class MyObservedObjectWrapper : ObservableObject {
var objects: [MyObservedObject]
init(objects: [MyObservedObject]) {
self.objects = objects
}
}
struct ObjectVisualizer: View {
@ObservedObject var wrapper : MyObservedObjectWrapper
init(_ objects: [MyObservedObject]) {
self.wrapper = MyObservedObjectWrapper(objects: objects)
}
var body: some View {
ForEach(wrapper.objects, id: \.id) {obj in
Text(obj.text)
}
}
}
struct ContentView: View {
var body: some View {
Container()
}
}
发生了什么:
-
MyObservedObject
具有唯一的ID,而不是依赖于
text
现场。
-
当按下“点击我”按钮时,它必须手动呼叫
objectWillChange.send()
因为否则ObservableObject不知道它正在更新(因为您正在修改引用类型的数组而不是值类型。
-
这个
ObjectVisualizer
视图不想只使用传入的引用类型数组重新呈现。因此,我将它们放在一个包装器对象中。这似乎触发了中所需的重新渲染
ForEach
做这样的事情不值得重构以获得结构模型吗?在我看来,可能不会,但当然,我对你的具体情况没有更多的了解。