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

SwiftUI中如何在init方法中获取Binding的包装值?

在SwiftUI的init方法中获取Binding包装值的解决方案

问题原因

在SwiftUI中,View的init方法执行时,Binding的包装值可能还未完成与父视图状态的同步——你这里的ChildView是在sheet中创建,父视图设置itemToEdit = thing和showSheet = true的操作,与ChildView的初始化存在时序差,导致init里直接访问self.itemToEdit拿到的是初始nil。


方案1:利用onAppear初始化状态变量

把name的初始化逻辑移到onAppear回调中,此时View已完成渲染,Binding的值已同步:

struct ChildView: View {
    @Binding var itemToEdit : Thing?
    @Environment(\.dismiss) var dismiss
    
    @State var name: String = ""

    init(itemToEdit: Binding<Thing?>) {
        self._itemToEdit = itemToEdit
    }
     
    var body: some View {
        NavigationView {
            Form {
                TextField("Name", text: $name)
            }
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Save") {
                        itemToEdit!.name = self.name
                        dismiss()
                    }
                }
            }
        }
        .onAppear {
            if let thing = itemToEdit {
                name = thing.name ?? ""
            }
        }
    }
}

方案2:直接绑定TextField到itemToEdit的name属性(更简洁)

既然itemToEdit是绑定的Thing实例,可直接将TextField与itemToEdit.name绑定,省去额外的@State变量:

struct ChildView: View {
    @Binding var itemToEdit : Thing?
    @Environment(\.dismiss) var dismiss

    init(itemToEdit: Binding<Thing?>) {
        self._itemToEdit = itemToEdit
    }
     
    var body: some View {
        NavigationView {
            Form {
                if let item = $itemToEdit {
                    TextField("Name", text: item.name ?? "")
                }
            }
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Save") {
                        dismiss()
                    }
                }
            }
        }
    }
}

注:这里使用item.name ?? ""是因为name是可选String,TextField需要非可选的Binding<String>,??操作符会生成一个绑定,当原值为nil时使用空字符串,修改时会自动将非空字符串赋值给原属性。

方案3:在init中通过Binding的wrappedValue直接获取(需确保父视图已赋值)

如果确定父视图在创建ChildView前已经完成itemToEdit的赋值,可以直接访问Binding的wrappedValue属性(注意处理可选值,避免崩溃):

struct ChildView: View {
    @Binding var itemToEdit : Thing?
    @Environment(\.dismiss) var dismiss
    
    @State var name: String

    init(itemToEdit: Binding<Thing?>) {
        self._itemToEdit = itemToEdit
        self.name = itemToEdit.wrappedValue?.name ?? ""
    }
     
    var body: some View {
        NavigationView {
            Form {
                TextField("Name", text: $name)
            }
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Save") {
                        itemToEdit!.name = self.name
                        dismiss()
                    }
                }
            }
        }
    }
}

注意:这种方式依赖父视图的赋值时序,如果父视图在创建ChildView时itemToEdit还未赋值,依然会拿到nil,所以推荐方案1或方案2更稳妥。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:40:36