繁体   English   中英

核心数据和 SwiftUI 多态性问题

[英]Core Data and SwiftUI polymorphism issues

将 SwiftUI 和用于处理核心数据的泛型类型放在一起时遇到了麻烦。

考虑以下示例:

在此处输入图像描述

Parent是抽象的。 FooBarParent的孩子,它们有一些自定义属性。

现在我想做的,大致是这样的:

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

我想将多态构建器添加到塑造数据或构建视图的核心数据实体中,以确认通用接口,这样我就可以在不进行强制转换/键入的情况下使用它们。

如果我尝试不通过扩展直接修改生成的核心数据实体,并且通过扩展确认协议不允许覆盖,编译器会抛出错误的问题。

好的,这是令人头疼的(至少对于疯狂的预览版而言),但它可以在运行时工作。 使用 Xcode 11.4 / iOS 13.4 进行测试。

由于我们需要在扩展中完成所有工作,因此想法是通过 Obj-C 消息传递使用调度,这是在此类要求下覆盖实现的实际可用的传递。

注意:使用模拟器或设备

演示

完整的测试模块

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM