簡體   English   中英

列表行內的SwiftUI @StateObject

[英]SwiftUI @StateObject inside List rows

當行嵌入到容器(如堆棧或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等結合時)?

以下是有關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移動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)
       }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM