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
相关产品推荐
相关产品推荐

