【问题标题】:SwiftUI @StateObject inside List rows列表行内的 SwiftUI @StateObject
【发布时间】:2020-11-18 12:48:51
【问题描述】:

当行嵌入到像堆栈或NavigationLink 这样的容器中时,SwiftUI 似乎不会为列表行保留@StateObjects。这是一个例子:

class MyObject: ObservableObject {
    init() { print("INIT") }
}

struct ListView: View {
    var body: some View {
        List(0..<40) { _ in
            NavigationLink(destination: Text("Dest")) {
                ListRow()
            }
        }
    }
}

struct ListRow: View {
    @StateObject var obj = MyObject()
    var body: some View {
        Text("Row")
    }
}

当您向下滚动列表时,您会看到 "INIT" 记录了每个出现的新行。但是向上滚动,您会看到 "INIT" 再次记录每一行 - 即使它们已经出现了。

现在删除NavigationLink:

List(0..<40) { _ in
    ListRow()
}

并且@StateObject 的行为与预期一致:每一行只有一个"INIT",没有重复。 ObservableObject 在视图刷新时保持不变。

SwiftUI 在持久化@StateObjects 时遵循什么规则?在此示例中,MyObject 可能正在存储重要的状态信息或下载远程资产 - 那么我们如何确保每行仅发生一次(与 NavigationLink 等结合使用时)?

【问题讨论】:

  • ListRow 可能不应该存储任何@StateObjects。相反,它们应该保留在行的外部,然后在初始化ListRow 时传入。

标签: ios swift swiftui


【解决方案1】:

以下是文档中关于 StateObject 的内容:

///     @StateObject var model = DataModel()
///
/// SwiftUI creates a new instance of the object only once for each instance of
/// the structure that declares the object. 

List 确实不会创建新的行实例,而是重用之前创建的并离开屏幕。但是NavigationLink 每次都会为标签创建新实例,所以你会看到这个。

您的情况可能的解决方案是将NavigationLink inside ListRow:

struct ListView: View {
    var body: some View {
        List(0..<40) { _ in
            ListRow()
        }
    }
}

struct ListRow: View {
    @StateObject var obj = MyObject()
    var body: some View {
       NavigationLink(destination: Text("Dest")) {     // << here !!
          Text("Row")
       }
    }
}

如果你想在没有导航的地方重复使用ListRow,你甚至可以将它们分开

struct LinkListRow: View {
    @StateObject var obj = MyObject()
    var body: some View {
       NavigationLink(destination: Text("Dest")) {
          ListRow(obj: obj)
       }
    }
}

【讨论】:

  • Once for each instance of the structure that declares the object。这就是为什么错误如此容易潜入的原因 - 没有保证(或文档)何时会创建一个新实例,它有时只是意外发生。 NavigationLinkStacks 是 2 个示例 - 即使它们的包含视图应该被“保留”,它们也会重新创建它们的内容。
猜你喜欢
  • 1970-01-01
  • 2022-07-19
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多