当具有不同值的相同 class object 作为数据源传递时,为什么不重新呈现视图
Why aren't views rerendered when the same class object with different values is passed as data source
我正在探索 SwiftUI,并且 运行 遇到了一些我不太明白的事情。
我创建了一个容器视图,可以按照 this post 中的描述获取数据,但我没有完全更改渲染视图中引用的 object,而是加载它的一些属性。
加载程序是容器视图观察到的ObservableObject
。当加载程序指示它(s 值)已更改时,容器视图重新加载其 body
属性 并显示带有新数据的渲染视图。但是,当需要加载的object为class时,并不是body
属性中的所有subview都重新加载。
这是我实现的一些"pseudo"代码。
protocol ValueLoader: Combine.ObservableObject {
associatedtype Value
var data: Value { get set }
func load()
}
struct ValueLoadingContainerView<ValueConsumer: View,
ValueContainer: ValueLoader>: View {
@ObservedObject var valueLoader: ValueContainer
let containedView: (ValueContainer.Value) -> ValueConsumer
init(_ loader: ValueContainer,
@ViewBuilder contained: @escaping (ValueContainer.Value) -> ValueConsumer) {
self.valueLoader = loader
self.containedView = contained
}
var body: some View {
containedView(valueLoader.data)
.onAppear(perform: load)
}
private func load() {
self.valueLoader.load()
}
}
class Object {
let id: String
var title: String?
func load(from ...) {
self.title = ...
}
}
struct ConcreteLoader: ValueLoader {
@Published var data: Object
func load() {
guard shouldLoad() else { return } // To prevent infinite recursion
...
// self.objectWillChange is synthesised by conforming to
// ObservableObject and having a property with @Published
self.objectWillChange.send()
self.data.load(from: ...)
}
}
struct ObjectRenderingView: View {
let object: Object
var body: some View {
Text(object.title ?? "ObjectRenderingView is waiting...")
}
}
let object = Object(id: "1", title: nil)
ValueLoadingContainer(ConcreteLoader(object),
contained: { obj in
Text(obj.title ?? "Text is waiting...") // 1
Divider()
ObjectRenderingView(object: obj) // 2
})
当加载程序加载了 object
的属性时,它再次调用传递给 object 的 @ViewBuilder
闭包,但现在它的属性被加载了。
如果我添加 print
语句,我清楚地看到 contained
@ViewBuilder
闭包被调用了两次:一次是卸载的 object 一次是加载的 object。这些都是一样的object,但是第二次,属性已经加载了。
Text
标签 (1) 已正确更新,从 "Text is waiting..." 更改为实际标题,但 ObjectRenderingView
(2) 未更新其子视图。
ObjectRenderingView
的 init
被新数据调用,但 body 属性 永远不会被访问。这向我表明 SwiftUI 认为数据没有改变并且不需要重新渲染。
我想我明白为什么它不起作用:obj
的身份没有改变,所以 SwiftUI 认为 ObjectRenderingView
不需要重新加载。由于值 obj.title
的标识已从 nil
更改为实际标题,因此重新加载 Text
视图。我不知道的是如何让 SwiftUI 也重新加载 ObjectRenderingView
。
谢谢!
应该是值类型。请查看 Xcode.
中 ObservedObject 的文档
If Value
is not value semantic, the updating behavior for any views
that make use of the resulting Binding
is unspecified.
我正在探索 SwiftUI,并且 运行 遇到了一些我不太明白的事情。
我创建了一个容器视图,可以按照 this post 中的描述获取数据,但我没有完全更改渲染视图中引用的 object,而是加载它的一些属性。
加载程序是容器视图观察到的ObservableObject
。当加载程序指示它(s 值)已更改时,容器视图重新加载其 body
属性 并显示带有新数据的渲染视图。但是,当需要加载的object为class时,并不是body
属性中的所有subview都重新加载。
这是我实现的一些"pseudo"代码。
protocol ValueLoader: Combine.ObservableObject {
associatedtype Value
var data: Value { get set }
func load()
}
struct ValueLoadingContainerView<ValueConsumer: View,
ValueContainer: ValueLoader>: View {
@ObservedObject var valueLoader: ValueContainer
let containedView: (ValueContainer.Value) -> ValueConsumer
init(_ loader: ValueContainer,
@ViewBuilder contained: @escaping (ValueContainer.Value) -> ValueConsumer) {
self.valueLoader = loader
self.containedView = contained
}
var body: some View {
containedView(valueLoader.data)
.onAppear(perform: load)
}
private func load() {
self.valueLoader.load()
}
}
class Object {
let id: String
var title: String?
func load(from ...) {
self.title = ...
}
}
struct ConcreteLoader: ValueLoader {
@Published var data: Object
func load() {
guard shouldLoad() else { return } // To prevent infinite recursion
...
// self.objectWillChange is synthesised by conforming to
// ObservableObject and having a property with @Published
self.objectWillChange.send()
self.data.load(from: ...)
}
}
struct ObjectRenderingView: View {
let object: Object
var body: some View {
Text(object.title ?? "ObjectRenderingView is waiting...")
}
}
let object = Object(id: "1", title: nil)
ValueLoadingContainer(ConcreteLoader(object),
contained: { obj in
Text(obj.title ?? "Text is waiting...") // 1
Divider()
ObjectRenderingView(object: obj) // 2
})
当加载程序加载了 object
的属性时,它再次调用传递给 object 的 @ViewBuilder
闭包,但现在它的属性被加载了。
如果我添加 print
语句,我清楚地看到 contained
@ViewBuilder
闭包被调用了两次:一次是卸载的 object 一次是加载的 object。这些都是一样的object,但是第二次,属性已经加载了。
Text
标签 (1) 已正确更新,从 "Text is waiting..." 更改为实际标题,但 ObjectRenderingView
(2) 未更新其子视图。
ObjectRenderingView
的 init
被新数据调用,但 body 属性 永远不会被访问。这向我表明 SwiftUI 认为数据没有改变并且不需要重新渲染。
我想我明白为什么它不起作用:obj
的身份没有改变,所以 SwiftUI 认为 ObjectRenderingView
不需要重新加载。由于值 obj.title
的标识已从 nil
更改为实际标题,因此重新加载 Text
视图。我不知道的是如何让 SwiftUI 也重新加载 ObjectRenderingView
。
谢谢!
应该是值类型。请查看 Xcode.
中 ObservedObject 的文档If
Value
is not value semantic, the updating behavior for any views that make use of the resultingBinding
is unspecified.