swiftui - SwiftUI - 滚动时,行子视图中的 StateObject 被初始化并多次取消初始化
问题描述
我想将 a 添加到显示在分段列表中的行的子视图中,以便在更新属性StateObject
时执行一些工作并更新子视图(例如下载图像)。该工作应在子视图出现时执行 ( )。@Published
StateObject
.onAppear { }
该行被初始化一次,并在滚动时出现/消失。添加项目时,视图会再次初始化(不一定重新绘制,但如果没有任何更改,这是正常的)。同样,子视图初始化一次,并在滚动时出现/消失。添加项目时,视图会再次初始化(不一定重新绘制,但如果没有任何更改,这是正常的)。
但是StateObject
当我滚动时,子视图中的 被初始化和 deinit 多次。它不应该,因为它是 aStateObject
而不是ObservedObject
. 为什么会这样?
当我将它添加StateObject
到行中时,它StateObject
会正确初始化一次(即使将新项目添加到列表中)并且永远不会 deinit。
下面提供的示例代码。
import SwiftUI
struct SectionTest: Identifiable {
var id: String { title }
var title: String
var items = [Item]()
}
struct Item: Identifiable {
var id: String { name }
var name: String
var section: String
}
class Loader: ObservableObject {
private var name: String
init(name: String) {
self.name = name
print("Loader • init \(name)")
}
func load() {
print("Loader • load \(name)")
}
deinit {
print("Loader • deinit \(name)")
}
}
struct LoaderView: View {
@StateObject private var loader: Loader
let name: String
init(name: String) {
print("LoaderView • init \(name)")
self.name = name
self._loader = StateObject(wrappedValue: Loader(name: "LoaderView ".appending(name)))
}
var body: some View {
Rectangle()
.frame(height: 200)
.onAppear { loader.load() }
.onAppear {
print("LoaderView • appear \(name)")
}
.onDisappear {
print("LoaderView • disappear \(name)")
}
}
}
struct RowView: View {
@StateObject private var loader: Loader
let name: String
init(name: String) {
print("RowView • init \(name)")
self.name = name
self._loader = StateObject(wrappedValue: Loader(name: "RowView ".appending(name)))
}
var body: some View {
VStack(alignment: .leading) {
Text(name)
.foregroundColor(.red)
LoaderView(name: name)
}
.onAppear {
print("RowView • appear \(name)")
}
.onDisappear {
print("RowView • disappear \(name)")
}
}
}
struct StateObjectListView: View {
@State private var items = [
Item(name: UUID().uuidString, section: "First"),
Item(name: UUID().uuidString, section: "First"),
Item(name: UUID().uuidString, section: "First"),
Item(name: UUID().uuidString, section: "Second"),
Item(name: UUID().uuidString, section: "Second"),
Item(name: UUID().uuidString, section: "Third"),
Item(name: UUID().uuidString, section: "Third"),
Item(name: UUID().uuidString, section: "Third")
]
private var sections: [SectionTest] {
Dictionary(grouping: items) { $0.section }
.map { SectionTest(title: $0.key, items: $0.value.sorted { $0.name < $1.name }) }
.sorted { $0.title < $1.title }
}
var body: some View {
NavigationView {
VStack {
Button("Add") {
let section = ["First", "Second", "Third"].randomElement()!
items.append(Item(name: UUID().uuidString, section: section))
}
ScrollView {
LazyVStack {
ForEach(sections) { section in
Section(header: Text(section.title).font(.caption2)) {
ForEach(section.items) { item in
RowView(name: item.name)
}
}
}
}
}
}
}
}
}
解决方案
推荐阅读
- kubernetes - Kubernetes PVC 删除 POD 的内容
- apache-flink - 失去检查点协调员后是否有可能恢复
- java - 不同类方法的组成
- reactjs - 在 goDaddy 主机上上传由 create-react-app 创建的 react 应用程序的步骤
- ruby-on-rails - 具有树节点属性的 Rails 树模型
- django - Django Cart - 产品的多个配置选项
- javascript - 减少编辑和删除文本之间的空间
- windows - 在不使用 OCR 的情况下从 Windows 屏幕上的矩形中提取文本
- c++ - 在 C++ 中的 OpenSSL 中为 SSL_read 设置连接超时
- python-3.x - 如何使用 Selenium Webdriver 定位按钮元素?