我很好奇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]';如果是故意的,则添加显式类型注释”。
有人有什么想法吗?
答案 0 :(得分:0)
这是因为您有一个通用约束。 AnyView
没有一般约束。您可以使用基础泛型View
实例化它,但是其Body
始终被声明为Never
。可能有编译器魔术在这里发生,因为我无法使用通用的无约束版本。
答案 1 :(得分:0)
这里是可能方法的演示。它经过简化,但显示了如何完成此操作的通用概念……或至少是一个方向。
完整的可编译工作模块。在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()
}
}