SwiftUI iOS16 表格可选字符串为 Keypath

3
如何为可选属性创建一列表格?在我的模型中,我是否需要将其解包以使其成为空字符串(如果它是“nil”)?
extension SomeObject {
    var someOptionalStringUnwrapped: String { return someOptionalString ?? "" }
}

Table(someObject) {
    TableColumn("One", value: \.someString)
    TableColumn("Two", value: \.someOptionalString) // <--shows error mentioned below
    TableColumn("Three", value: \.someOptionalStringUnwrapped) // <--compiles
}

关键路径的值类型“String?”无法转换为上下文类型“String”。

解决方案

对于简单的属性,如字符串和数字,取消包装策略似乎是解决此问题的最简单方法(可以使用通用扩展,如答案中所述,也可以针对每个属性进行设置,如问题中所述)。对于更复杂的用户界面,我们始终可以退而求其次,采用自定义UI:

TableColumn("DEMO") { someObject in
    ...
    Text("\(someObject.someValue)")
    ...
}
1个回答

4

正如你所说,对模型中的可选项进行解包是解决此问题的一种方法。另一种解决方案是声明一个关于可选项的扩展,这样你就不必为每个属性都这样做。

// this could also be "where Wrapped: StringProtocol"
extension Optional where Wrapped == String {
    var unwrapOrEmpty: Wrapped {
        self ?? ""
    }
}

TableColumn("Given Name", value: \.someOptionalString.unwrapOrEmpty)

或者,在所有RangeReplaceableCollection上创建一个扩展,该扩展符合String

extension Optional where Wrapped: RangeReplaceableCollection {
    var unwrapOrEmpty: Wrapped {
        self ?? .init() // init() makes an empty collection
    }
}

第三种方法是使用另一个重载的TableColumn,例如this one,它允许您指定自己的Content视图。
init(_ titleKey: LocalizedStringKey, @ViewBuilder content: @escaping (RowValue) -> Content)

您可以在TableColumn上编写一个扩展,该扩展委托给上述初始化程序:

extension TableColumn where RowValue: Identifiable, Sort == Never, Content == Text, Label == Text {
    init(
        _ titleKey: LocalizedStringKey,
        value: KeyPath<RowValue, String?>
    ) {
        self.init(titleKey) { rowValue in
            Text(rowValue[keyPath: value] ?? "")
        }
    }
}

写方便的扩展方法是有意义的,但这意味着需要使用强制解包的方式。谢谢信息。 - Deitsch
哇,太棒了!对很多其他可选情况也非常有帮助,比如 CoreData! - ChrisR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接