Как создать TableColumn для необязательного свойства? Должен ли я развернуть его в моей модели, чтобы сделать его пустой строкой, если это 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'
Для простых свойств, таких как строки и числа, стратегия развертывания кажется самым простым способом решить эту проблему (либо общее расширение, как в ответе, либо для каждого свойства, как в вопросе). Для более сложного пользовательского интерфейса всегда можно вернуться к пользовательскому интерфейсу:
TableColumn("DEMO") { someObject in
...
Text("\(someObject.someValue)")
...
}





Как вы сказали, одним из способов решения этой проблемы является развертывание необязательного в модели. Другим решением было бы объявить расширение для опций, поэтому вам не нужно делать это для каждого свойства, подобного этому.
// 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, например вот эту, которая позволяет указать собственное представление 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] ?? "")
}
}
}
Вау, какой отличный ответ. Также очень полезно для многих других необязательных случаев, например. CoreData!
Имеет смысл писать удобные расширения, но это означает, что распаковка — это путь. Спасибо за информацию