Могу ли я передать общий тип в представление SwiftUI как @Bindable?

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)
        ]
    }
}

Спасибо всем, кто может мне помочь!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
151
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ошибка содержит очень важную информацию:

Обернутое значение должно быть объектом

Вам нужно 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 }
}

Другие вопросы по теме