【问题标题】:Make a list of Structs conform to a protocol SwiftUI使结构列表符合协议 SwiftUI
【发布时间】:2021-09-28 07:52:22
【问题描述】:

我有一个自定义协议说

protocol CustomProtocol {}

我有一个自定义结构说

struct CustomStruct: View, CustomProtocol

如何使 (CustomStruct, CustomStruct) 符合 CustomProtocol

我有一个具有 init 函数的自定义 ViewBuilder,

init<views>(@ViewBuilder content: @escaping () -> TupleView<Views>)

现在我只希望接受符合 CustomProtocol 的视图

例子:

struct CustomStruct: View {
var views: [AnyView]

init<Views: CustomProtocol>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
    self.views = content().getViews
}

我为 getViews 变量添加了元组视图的扩展:

extension TupleView {
var getViews: [AnyView] {
    makeArray(from: value)
}

private struct GenericView {
    let body: Any
    
    var anyView: AnyView? {
        AnyView(_fromValue: body)
    }
}

private func makeArray<Tuple>(from tuple: Tuple) -> [AnyView] {
    func convert(child: Mirror.Child) -> AnyView? {
        withUnsafeBytes(of: child.value) { ptr -> AnyView? in
            let binded = ptr.bindMemory(to: GenericView.self)
            return binded.first?.anyView
        }
    }
    
    let tupleMirror = Mirror(reflecting: tuple)
    return tupleMirror.children.compactMap(convert)
}

}

【问题讨论】:

  • 你不能。元组不能符合协议。你这样做是为了解决什么问题?
  • 我有一个自定义 ViewBuilder,它有一个初始化函数 init(@ViewBuilder content: @escaping () -> TupleView),现在我只想要符合 CustomProtocol 的视图被接受
  • edit您的问题提供更多详细信息。
  • init&lt;Views: CustomProtocol&gt; 不适合你?
  • @Cristik TupleView 是 SwiftUI 的一部分。我认为他们不需要添加有关它的详细信息?

标签: swift swiftui swift-protocols


【解决方案1】:

我能想到的唯一方法就是重塑你自己的ViewBuilder

@resultBuilder
struct MyCustomViewBuilder {
    static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View & CustomProtocol, C1 : View & CustomProtocol {
        ViewBuilder.buildBlock(c0, c1)
    }
    static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0 : View & CustomProtocol, C1 : View & CustomProtocol, C2: View & CustomProtocol {
        ViewBuilder.buildBlock(c0, c1, c2)
    }

    // and so on...
}

ViewBuilder 具有最多 10 个视图的 buildBlock 重载(这就是为什么您不能在 ViewBuilder 中放置超过 10 个视图的原因),因此如果您也想写最多 10 个重载.不幸的是,没有办法使用可变参数,因为View 有关联的类型:(

那么你可以做例如:

struct CustomStack<Views>: View {
    var body: some View {
        content
    }
    
    let views: [AnyView]
    let content: TupleView<Views>

    // note the change from @ViewBuilder to @CustomViewBuilder
    init(@MyCustomViewBuilder content: @escaping () -> TupleView<Views>) {
        let view = content()
        self.views = view.getViews
        self.content = view
    }
}

现在如果你这样做:

CustomStack {
    Text("Hello")
    Text("World")
}

编译器会抱怨Text 不符合CustomProtocol

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多