我创建了一个简单的SwiftUI应用程序,该应用程序在列表中显示来自网络的图像。所有图像均在后台加载。至此,所有工作均按预期进行。但是,如果在加载过程中确实触发了一些State变量,那么我的所有单元格都将重新初始化。
让我们看看代码:
struct ImageView: View {
@ObservedObject var imageLoader = ImageLoader()
var body: some View {
VStack {
if self.imageLoader.isLoaded {
DisplayImage(self.imageLoader.image)
} else {
Text("Loading...")
}
}
.onAppear {
self.imageLoader.loadImage()
}
}
}
struct TableView: View {
@State var someTrigger: Bool = false;
var body: some View {
List {
ForEach( someCollection, id: \.self) {
ImageView()
}
}
}
}
因此,如果在加载图像时触发了“ someTrigger”,则所有单元将被重新初始化,imageLoader将被重新初始化,.onAppear将不会被调用,图像将不会加载。
这是预期的行为吗?在那种情况下,我只是不能用某些后台任务来初始化我的模型?
谢谢。
答案 0 :(得分:0)
我认为可以通过传递imageLoader
而不是在视图本身中初始化为您解决。我实际上会建议使集合对象具有ImageLoader
来更新某些@Published
图像属性。尝试设置模型以完成所有繁重的工作,然后让视图仅声明模型的每个状态应具有的状态。
答案 1 :(得分:0)
SwiftUI 2.0
使用StateObject
包装器,它将不允许重新创建加载器
struct ImageView: View {
@StateObject var imageLoader = ImageLoader()
SwiftUI 1.0
可能的解决方案(可能取决于您的真实代码)是使ImageView
显式地等于某个属性(例如,仅id
),即。排除imageLoader
本身。这可以使渲染引擎有机会在状态更改时不替换ImageView
例如
struct ImageView: View, Equatable {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.url == rhs.url
}
let url: URL // some unique property
@ObservedObject var imageLoader = ImageLoader()
// ... other code
}
并使用
ForEach( someCollection, id: \.self) {
ImageView().equatable() // << here !!
}