Swift новичок здесь, пожалуйста, будьте любезны! Как я могу преобразовать это представление SwiftUI в версию, которая принимает в качестве входных данных различные типы элементов?
У меня есть это представление в моем приложении iOS:
struct EditMeshType: View {
@Bindable var item: MeshType
private let navTitle: String = "Edit Mesh Types"
var body: some View {
Form {
TextField("Name", text: $item.name)
Toggle("Active?", isOn: $item.activeFlag)
}
.navigationTitle(navTitle)
.navigationBarTitleDisplayMode(.inline)
}
}
Это представление вызывается из другого представления, и я передаю определенный «элемент» типа «MeshType», чтобы позволить пользователю изменить имя или активный флаг. В основном представлении используется SwiftData, а «item» является членом массива MeshType, который является частью объявления @Query. Я вставил объект MeshType ниже.
Я хочу передать в это представление типы, отличные от MeshType. Например, у меня есть другой тип, называемый ArtifactType, который также имеет свойства «name» и «activeFlag». У меня есть много качеств, которые следуют этому шаблону. Я не хочу создавать отдельные представления для каждого из них, если вместо этого я могу создать общее представление. Это упрощенный пример, но надеюсь, будет достаточно сказать, что у меня есть причины не желать объединять эти (похожие, но не идентичные) запросы поиска в один класс с классификатором «типа».
Я попробовал это:
struct EditLookup<T>: View {
@Bindable var item: T
private let navTitle: String = "Edit Lookup Value"
var body: some View {
Form {
TextField("Name", text: $item.name)
Toggle("Active?", isOn: $item.activeFlag)
}
.navigationTitle(navTitle)
.navigationBarTitleDisplayMode(.inline)
}
}
но строка @Bindable выдает ошибку компилятора: «init(wrappedValue:)» недоступен: обернутое значение должно быть объектом, соответствующим Observable»
Это меня смущает, потому что MeshType использует макрос @Model, который, как я думал, обеспечивает соответствие Observable. Каким-то образом универсальная версия не знает, что любой тип T соответствует Observable.
Итак, я попытался сослаться на протокол для T:
protocol Lookup: Observable {
var name: String { get set }
var sortOrder: Int { get set }
var metaCreateDate: Date { get set }
var activeFlag: Bool { get set }
var preventDelete: Bool { get }
var logentries: [LogEntry]? { get }
}
и согласовать тип модели MeshType с этим протоколом, а затем отредактировать мое общее представление, чтобы ссылаться на протокол как на ограничение:
struct EditLookup<T: Lookup>: View {
@Bindable var item: T
private let navTitle: String = "Edit Lookup Value"
var body: some View {
Form {
TextField("Name", text: $item.name)
Toggle("Active?", isOn: $item.activeFlag)
}
.navigationTitle(navTitle)
.navigationBarTitleDisplayMode(.inline)
}
}
но это дает мне ту же ошибку в компиляторе.
Я делаю это неправильно? есть ли лучший способ достичь моей цели (передать различные типы в общее представление редактирования?)
Вот моя модель MeshType. MeshType — одно из многих полей поиска в LogEntry. Другие поля поиска имеют аналогичную структуру и все они соответствуют поиску.
@Model
class MeshType: Lookup {
var name: String
var sortOrder: Int
var metaCreateDate: Date
var activeFlag: Bool
@Relationship(inverse: \LogEntry.meshType)
var logentries: [LogEntry]?
var preventDelete: Bool {
logentries?.count ?? 0 > 0
}
init(name: String, sortOrder: Int = 0) {
self.name = name
self.sortOrder = sortOrder
self.metaCreateDate = Date.now
self.activeFlag = true
}
static var sample: [MeshType] {
[
.init(name: "Window Screen", sortOrder: 1),
.init(name: "Hardware Cloth", sortOrder: 2)
]
}
}
Спасибо всем, кто может мне помочь!
Ошибка содержит очень важную информацию:
Обернутое значение должно быть объектом
Вам нужно Lookup
соответствовать AnyObject
, поскольку @Bindable
ожидает класса. Я удивлен, что протокол Observable
этого еще не делает.
protocol Lookup: Observable, AnyObject {
var name: String { get set }
var sortOrder: Int { get set }
var metaCreateDate: Date { get set }
var activeFlag: Bool { get set }
var preventDelete: Bool { get }
}