代码之家  ›  专栏  ›  技术社区  ›  Hundley

列表行中的SwiftUI@StateObject

  •  0
  • Hundley  · 技术社区  · 5 年前

    SwiftUI似乎并没有持续下去 @StateObjects 对于列表行,当该行嵌入堆栈或 NavigationLink .举个例子:

    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" 为显示的每一新行记录。但是向上滚动,你会看到 “初始化” 每一行都会重新记录,即使它们已经出现。

    现在移除 导航链接 :

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

    还有 @StateObject 表现如预期:正好一个 “初始化” 每一行,没有重复。这个 ObservableObject 在视图刷新中保持。

    SwiftUI在坚持时遵循哪些规则 @状态对象 ? 在这个例子中 MyObject 可能是存储重要的状态信息或下载远程资产——那么我们如何确保每行只发生一次(与 导航链接 等等)?

    0 回复  |  直到 5 年前
        1
  •  2
  •   Asperi    5 年前

    以下是有关文档的内容 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 实际上并不创建新的row实例,而是重用以前创建的并在屏幕外运行的实例。然而 NavigationLink 每次都为label创建新实例,所以您可以看到这一点。

    你的案子可能的解决方案是搬家 导航链接 在…内 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")
           }
        }
    }
    

    如果你想重复使用,你甚至可以把它们分开 利斯特罗 没有导航的地方

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