You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI首次从父视图传值至SecondView时出现值错误问题求助

问题重现

通过分段选择器修改布尔值isRunning的状态后,首次点击按钮打开SecondView时,视图接收到的是初始值true而非修改后的false;但关闭视图后重新切换状态再打开,就能获取正确值。

主视图代码

struct ContentView: View {
    @State private var onOffSegments = 1
    @State private var isRunning = true
        
    @State private var secondViewIsPresented = false
    
    var body: some View {
        VStack {
            Picker("", selection: $onOffSegments) {
                Text("Started")
                    .tag(1)
                Text( "Turned Off")
                    .tag(2)
            }
            .pickerStyle(.segmented)
            .onChange(of: onOffSegments, perform: { value in
                if value == 1{
                    isRunning = true
                    print("Is Running:\(isRunning)")
                }else{
                    isRunning = false
                    print("Is Running: \(isRunning)")
                }
            })
            
            Button("Show Second View"){
                secondViewIsPresented = true
            }
        }
        .padding()
        .sheet(isPresented: $secondViewIsPresented){
            SecondView(isRunning: isRunning)
        }
    }
}

第二个视图代码

struct SecondView: View {
    var isRunning: Bool
    
    var body: some View {
        Text("Second View")
            .onAppear{
                print("OnAppear SecondView, Is Running: \(isRunning)")
            }
    }
}

问题原因

SwiftUI中使用sheet(isPresented:)时,闭包内的视图会在父视图首次渲染时就被创建,并捕获当时的isRunning值。首次启动应用时isRunning初始为true,这个值被SecondView实例保存;后续修改isRunning时,已创建的SecondView实例不会重新捕获新值,所以第一次打开时仍用初始值。而关闭视图后,该实例被销毁,再次打开时会重新创建SecondView,此时才会捕获最新的isRunning值,因此第二次能得到正确结果。

解决方案

方案1:用sheet(item:)替代sheet(isPresented:)

通过绑定可选值触发sheet,每次打开都会重新创建视图并捕获最新状态:

struct ContentView: View {
    @State private var onOffSegments = 1
    @State private var isRunning = true
    @State private var secondViewTrigger: Bool?
    
    var body: some View {
        VStack {
            Picker("", selection: $onOffSegments) {
                Text("Started").tag(1)
                Text("Turned Off").tag(2)
            }
            .pickerStyle(.segmented)
            .onChange(of: onOffSegments) { value in
                isRunning = value == 1
                print("Is Running:\(isRunning)")
            }
            
            Button("Show Second View"){
                secondViewTrigger = isRunning
            }
        }
        .padding()
        .sheet(item: $secondViewTrigger) { currentValue in
            SecondView(isRunning: currentValue)
        }
    }
}

extension Bool: Identifiable {
    public var id: Self { self }
}

方案2:让SecondView接收绑定值

将isRunning改为绑定类型,让视图实时读取最新状态:

struct SecondView: View {
    @Binding var isRunning: Bool
    
    var body: some View {
        Text("Second View")
            .onAppear{
                print("OnAppear SecondView, Is Running: \(isRunning)")
            }
    }
}

// 主视图中传递绑定
.sheet(isPresented: $secondViewIsPresented){
    SecondView(isRunning: $isRunning)
}

方案3:用ObservableObject管理状态

将状态放到引用类型的对象中,利用其特性让视图感知状态变化:

class AppState: ObservableObject {
    @Published var isRunning = true
}

struct ContentView: View {
    @State private var onOffSegments = 1
    @StateObject private var appState = AppState()
    @State private var secondViewIsPresented = false
    
    var body: some View {
        VStack {
            Picker("", selection: $onOffSegments) {
                Text("Started").tag(1)
                Text("Turned Off").tag(2)
            }
            .pickerStyle(.segmented)
            .onChange(of: onOffSegments) { value in
                appState.isRunning = value == 1
                print("Is Running:\(appState.isRunning)")
            }
            
            Button("Show Second View"){
                secondViewIsPresented = true
            }
        }
        .padding()
        .sheet(isPresented: $secondViewIsPresented){
            SecondView(appState: appState)
        }
    }
}

struct SecondView: View {
    @ObservedObject var appState: AppState
    
    var body: some View {
        Text("Second View")
            .onAppear{
                print("OnAppear SecondView, Is Running: \(appState.isRunning)")
            }
    }
}

内容的提问来源于stack exchange,提问作者fs_tigre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:35:26