如何在 SwiftUI 中实现像 AnyView 这样的类型擦除结构?

nal*_*dad 8 swiftui

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

例如:

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

而我的实现:

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

Run Code Online (Sandbox Code Playgroud)

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

有没有人有任何想法?

Asp*_*eri 5

这是可能方法的演示。它经过简化,但显示了如何完成此操作的一般想法......或者至少是一个方向。

完整的可编译和工作模块。在 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()
    }
}
Run Code Online (Sandbox Code Playgroud)


Pro*_*in8 0

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