SwiftUI - 导航时视图是否保持活动状态?

SwiftUI - Are views kept alive while navigating?

我在使用 NavigationLinks 和 ObservableObject 时遇到错误。我不太明白为什么,因为我不明白在导航时视图和数据发生了什么。这是一些伪代码来说明问题:

class Settings: ObservableObject {
    @Published var data: [Int] = [0, 1, 2, 3, 4, 5]
}

struct ContentView: View {
    @State var new_view: Bool = false
    @ObservedObject var content_view_settings = Settings()
    
    var body: some View {
        NavigationView {
            VStack {
                Button(action: {
                    DeleteLastItem()
                }) {
                    Text("Delete last item")
                }

                Button(action: {
                    self.new_view = true
                }) {
                    Text("New View")
                }
                
                NavigationLink(destination: NewView(new_view_settings: content_view_settings), isActive: $new_view) {
                    EmptyView()
                }
            }
        }
    }
}

struct NewView: View {
    @ObservedObject var new_view_settings: Settings
    @State var index = -1
    
    var body: some View {
        VStack {
            Button(action: {
                self.index = self.new_view_settings.count - 1
            }) {
                Text("change index")
            }

            if self.index > -1 {
                Text("\(self.new_view_settings.data[index])")
            }  
        }
    }
}

问题描述是这样的:

我有一个带有 ObservedObject 的视图,我在导航时将其传递给后续视图。该子视图访问数组的最后一个元素,但它仅在通过单击按钮验证索引变量后才执行此操作。然后仅在验证索引后才呈现文本。

现在,假设我验证了索引,因此在此示例中它等于 5。然后我导航回原始视图。如果我删除最后一个元素,索引 5 将不再有效。一旦删除最后一个元素,我就会收到无效索引错误并且模拟器崩溃。

但是假设我向后导航并且没有删除最后一个元素。然后当我向前导航时,索引变量被重置。

因为我遇到崩溃,这意味着视图仍然存在并且正在更新或其他东西,但是当我再次导航到它时,视图会重新加载。这是否意味着视图在再次初始化之前一直有效?这是人为的代码,但它本质上是我遇到的问题。我认为原始代码会有点难以理解。

Does this mean the view is alive until it gets initialized again?

是的,即使在您导航回父视图后视图可能仍然存在。


为了更好地理解正在发生的事情 运行 在 iPad 模拟器(最好是水平模式)上使用相同的代码。您会注意到 NavigationView 分为两部分:masterdetail - 这样您就可以同时看到父项和子项立即查看。

现在,如果您根据问题执行相同的实验,您将看到子视图仍然存在,即使您向后导航也是如此。 iOS.

也是如此

防止这种情况的一种方法是检查数组中是否存在索引:

struct NewView: View {
    @ObservedObject var new_view_settings: Settings
    @State var index = -1

    var body: some View {
        VStack {
            Button(action: {
                //self.index = self.new_view_settings.count - 1
            }) {
                Text("change index")
            }

            // check if `index` is in array
            if self.index > -1 && self.index < self.new_view_settings.data.count {
                Text("\(self.new_view_settings.data[index])")
            }
        }
    }
}

注意:通常我不建议在 SwiftUI 视图中处理索引 - 通常有更好的方法来传递数据。处理指数是 有风险的