Log*_*gan 5 swift swiftui combine
我有一个可能存在的父状态:
class Model: ObservableObject {
@Published var name: String? = nil
}
Run Code Online (Sandbox Code Playgroud)
如果该状态存在,我想显示一个子视图。在此示例中,显示name.
如果name可见,我希望它能够显示和编辑。我希望它是双向可编辑的,这意味着如果Model.name发生更改,我希望它推送到 ChildUI,如果 ChildUI 编辑它,我希望它反映回Model.name.
但是,如果Model.name变成了nil,我想ChildUI隐藏。
当我这样做时,通过展开,那么现在控制该状态的人Model.name只会捕获第一个值。Child后续更改不会推送到上游,因为它不是Binding.
问题
当可选存在时,我可以将非可选上游绑定到可选吗?(这些词合适吗?)
完整示例
import SwiftUI
struct Child: View {
// within Child, I'd like the value to be NonOptional
@State var text: String
var body: some View {
TextField("OK: ", text: $text).multilineTextAlignment(.center)
}
}
class Model: ObservableObject {
// within the parent, value is Optional
@Published var name: String? = nil
}
struct Parent: View {
@ObservedObject var model: Model = .init()
var body: some View {
VStack(spacing: 12) {
Text("Demo..")
// whatever Child loads the first time will retain
// even on change of model.name
if let text = model.name {
Child(text: text)
}
// proof that model.name changes are in fact updating other state
Text("\(model.name ?? "<waiting>")")
}
.onAppear {
model.name = "first change of optionality works"
loop()
}
}
@State var count = 0
func loop() {
async(after: 1) {
count += 1
model.name = "updated: \(count)"
loop()
}
}
}
func async(_ queue: DispatchQueue = .main,
after: TimeInterval,
run work: @escaping () -> Void) {
queue.asyncAfter(deadline: .now() + after, execute: work)
}
struct OptionalEditingPreview: PreviewProvider {
static var previews: some View {
Parent()
}
}
Run Code Online (Sandbox Code Playgroud)
rob*_*off 18
Child应该将 aBinding设为非可选字符串,而不是使用@State,因为您希望它与其父级共享状态:
struct Child: View {
// within Child, I'd like the value to be NonOptional
@Binding var text: String
var body: some View {
TextField("OK: ", text: $text).multilineTextAlignment(.center)
}
}
Run Code Online (Sandbox Code Playgroud)
Binding有一个将 a 转换为 的初始值设定项Binding<V?>,您Binding<V>?可以像这样使用它:
if let binding = Binding<String>($model.name) {
Child(text: binding)
}
Run Code Online (Sandbox Code Playgroud)
如果你因此而崩溃,这是 SwiftUI 中的一个错误,但你可以像这样解决它:
if let text = model.name {
Child(text: Binding(
get: { model.name ?? text },
set: { model.name = $0 }
))
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4888 次 |
| 最近记录: |