Основные данные и проблемы полиморфизма SwiftUI - PullRequest
1 голос
/ 03 мая 2020

Не удается собрать вместе SwiftUI и обобщенные типы c для обработки базовых данных.

Рассмотрим следующий пример:

enter image description here

Parent является абстрактным. Foo и Bar являются потомками Parent, и у них есть некоторые пользовательские атрибуты.

Теперь я хочу примерно следующее:

protocol EntityWithView {
    associatedtype T: View
    func buildView() -> T
}

extension Parent: EntityWithView {
    func buildView() -> some View {
        fatalError("Re-implement in child")
    }
}

extension Foo {
    override func buildView() -> some View {
        return Text(footribute)
    }
}

extension Bar {
    override func buildView() -> some View {
        return Text(atrribar)
    }
}

struct ViewThatUsesCoreDataAsModel: View {
    let entities: [Parent]

    var body: some View {
        ForEach(entities) { entity in
            entity.buildView()
        }
    }
}

Я бы хотел добавить polymorphi c builder к моим основным объектам данных, которые формируют данные или представления построения, которые подтверждают в общий интерфейс, так что я могу использовать их без приведения / ввода.

Проблема в том, что компилятор выдает ошибки, если я пытаюсь изменить сгенерированный объект данных Core напрямую, а не через расширение, и подтверждение протокола, хотя расширение не допускает переопределения.

1 Ответ

0 голосов
/ 06 мая 2020

Хорошо, это головокружительно (по крайней мере, для предварительного просмотра, который сошел с ума), но он работает во время выполнения. Протестировано с Xcode 11.4 / iOS 13.4.

Поскольку нам нужно сделать все в расширении, идея состоит в том, чтобы использовать диспетчеризацию через обмен сообщениями Obj- C, фактически доступный проход для переопределения реализации при таких требованиях.

Примечание: используйте симулятор или устройство

demo

Полный тестовый модуль

protocol EntityWithView {
    associatedtype T: View
    var buildView: T { get }
}

extension Parent {
    // allows to use Objective-C run-time messaging by complete
    // type erasing.
    // By convention subclasses
    @objc func generateView() -> Any {
        AnyView(EmptyView()) // << safe
        //fatalError("stub in base") // << alternate
    }
}

extension Parent: EntityWithView {
    var buildView: some View {
        // restory SwiftUI view type from dispatched message
        guard let view = self.generateView() as? AnyView else {
            fatalError("Dev error - subview must generate AnyView")
        }
        return view
    }
}

extension Foo {
    @objc override func generateView() -> Any {
        AnyView(Text(footribute ?? ""))
    }
}

extension Bar {
    @objc override func generateView() -> Any {
        AnyView(Text(attribar ?? ""))
    }
}

struct ViewThatUsesCoreDataAsModel: View {
    let entities: [Parent]

    var body: some View {
        VStack {
            ForEach(entities, id: \.self) { entity in
                entity.buildView
            }
        }
    }
}

struct DemoGeneratingViewInCoreDataExtension: View {
    @Environment(\.managedObjectContext) var context
    var body: some View {
        ViewThatUsesCoreDataAsModel(entities: [
           Foo(context: context), 
           Bar(context: context)
        ])
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...