SwiftUI中NavigationLink目标视图init提前执行问题求助
问题原因
你用的那种NavigationLink写法,destination是直接传入视图实例,SwiftUI会在父视图渲染阶段就创建这个实例,不管isActive有没有触发,所以目标视图的init会提前执行。
解决办法
方法1:改用闭包形式的NavigationLink(推荐)
把目标视图的创建逻辑放到闭包里,这样只有当isActive变为true时,才会执行闭包创建视图实例,完美避免提前初始化。
示例代码:
struct ContentView: View { @State private var isActive = false @State private var x = 1 var body: some View { NavigationStack { Button("跳转") { x = 2 isActive = true } NavigationLink(isActive: $isActive) { // 这里的视图创建只会在跳转触发时执行 SecondView(x: x) } label: { EmptyView() } } } } struct SecondView: View { let x: Int init(x: Int) { self.x = x print("SecondView init, x: \(x)") } var body: some View { Text("Second View: \(x)") } }
测试下会发现,只有点击按钮触发跳转时,才会打印SecondView init,而且能拿到最新的x值。
方法2:用LazyView包装目标视图
如果因为场景限制必须用原来的destination参数形式,可以自定义一个LazyView来延迟视图的创建:
// 自定义延迟加载视图 struct LazyView<Content: View>: View { let build: () -> Content init(_ build: @autoclosure @escaping () -> Content) { self.build = build } var body: Content { build() } }
然后在NavigationLink里这样用:
NavigationLink(destination: LazyView(SecondView(x: x)), isActive: $isActive) { EmptyView() }
LazyView会把视图的创建延迟到真正需要渲染的时候,也就是跳转触发时。
不推荐的方案:通过参数值区分初始化
如果业务里实在要靠参数判断是否执行初始化逻辑,虽然能临时解决,但会让视图逻辑变复杂,比如:
struct SecondView: View { let x: Int? init(x: Int?) { guard let validX = x, validX != 1 else { // 初始状态不执行业务初始化 self.x = 0 return } self.x = validX // 这里放跳转时才需要的初始化逻辑 print("执行业务初始化, x: \(validX)") } var body: some View { Text("Second View: \(x ?? 0)") } }
这种方式只是绕开问题,不是根本解决,优先选前两种方法。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

