【问题标题】:How to implement a type erased struct like AnyView in SwiftUI?如何在 SwiftUI 中实现像 AnyView 这样的类型擦除结构?
【发布时间】:2019-12-14 07:38:04
【问题描述】:

我很好奇 SwiftUI 中 AnyView 的默认实现。如何将不同泛型类型的结构体放入协议数组中?

例如:

let a = AnyView(Text("hello"))
let b = AnyView(Image(systemName: "1.circle"))
let genericViews = [a, b] // No compile error

还有我的实现:

struct TypeErasedView<V: View>: View {
    private var _view: V
    init(_ view: V) {
        _view = view
    }
    var body: V {
        _view
    }
}

let a = TypeErasedView(Text("Hello"))
let b = TypeErasedView(Image(systemName: "1.circle"))
let genericViews = [a, b] // compile error

编译错误将是“只能将异构集合文字推断为'[Any]';如果这是故意的,请添加显式类型注释”。

有人有什么想法吗?

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    这是一个可能的方法的演示。它被简化了,但显示了如何做到这一点的一般想法......或者至少是一个方向。

    完全可编译和工作的模块。在 Xcode 11.2 / iOS 13.2 上测试

    import SwiftUI
    
    private protocol TypeErasing {
        var view: Any { get }
    }
    
    private struct TypeEraser<V: View>: TypeErasing {
        let orinal: V
        var view: Any {
            return self.orinal
        }
    }
    
    public struct MyAnyView : View {
        public var body: Never {
            get {
                fatalError("Unsupported - don't call this")
            }
        }
    
        private var eraser: TypeErasing
        public init<V>(_ view: V) where V : View {
            eraser = TypeEraser(orinal: view)
        }
    
        fileprivate var wrappedView: Any { // << they might have here something specific
            eraser.view
        }
    
        public typealias Body = Never
    }
    
    
    struct DemoAnyView: View {
        let container: [MyAnyView]
        init() {
            let a = MyAnyView(Text("Hello"))
            let b = MyAnyView(Image(systemName: "1.circle"))
            container = [a, b]
        }
    
        var body: some View {
            VStack {
                // dynamically restoring types is different question and might be
                // dependent on Apple's internal implementation, but here is
                // just a demo that it works
                container[0].wrappedView as! Text
                container[1].wrappedView as! Image
            }
        }
    }
    
    struct DemoAnyView_Previews: PreviewProvider {
        static var previews: some View {
            DemoAnyView()
        }
    }
    

    【讨论】:

      【解决方案2】:

      这是因为你的有一个通用的约束。 AnyView 没有通用约束。您使用底层泛型View 对其进行实例化,但其Body 始终声明为Never。这里可能会发生编译器魔法,因为我无法使用通用的无约束版本。

      【讨论】:

        猜你喜欢
        • 2016-06-27
        • 1970-01-01
        • 2014-04-11
        • 2021-09-01
        • 1970-01-01
        • 2017-10-24
        • 1970-01-01
        • 1970-01-01
        • 2010-12-13
        相关资源
        最近更新 更多