【发布时间】:2020-07-23 05:58:47
【问题描述】:
抱歉,如果这个问题有点抽象,但在这里:
API 返回由几个简单字段组成的资源列表。其中一个字段(示例中的“view-id”)告诉客户端在呈现数据时使用哪个 SwiftUI View。
[
{
"title": "Example Title"
"image": "https://www.example.com/some/image.png"
"view-id": "text-row" // tells the client to use, say, `TextRowView`
},
{
"title": "A Second Title"
"image": "https://www.example.com/some/other/image.png"
"view-id": "image-row" // tells the client to use, say, `ImageRowView`
}
]
我的目标是找到一种可扩展的方式,以允许在运行时根据 API 中的 view-id 选择 View 类型。
为了解决这个问题,我定义了以下协议来描述可以创建视图的类型
protocol MyViewBuilder {
associatedtype Content: View
func buildView(data: Data) -> Content
}
/// concrete implementation of a `MyViewBuilder`
struct MyExampleViewBuilder {
func buildView(data: Data) -> Text {
Text(data.string)
}
}
我已经定义了以下协议来将 API 中的“view-id”映射到特定类型的视图:
protocol MyViewDescriptor {
associatedtype Content: View
var id: String { get }
}
/// concrete implementation for a `MyViewDescriptor`
struct MyExampleDescriptor {
associatedtype Content: Text
var id: String = "text-row"
}
现在,我构建了一个允许注册和访问这些片段的类型,如下所示:
class MyGlueCode: MyViewBuilder {
func register<D, B>(_ descriptor: D, viewBuilder: B) where D: MyViewDescriptor,
B: MyViewBuilder,
D.Content == B.Content {...}
func buildView<D, Content>(descriptor: D, data: Data) -> Content where D: MyViewDescriptor, Content == D.Content { ... }
}
现在上面的代码可以通过一点类型擦除来工作,但我正在努力的是如何为buildView(descriptor:data:) 保留/生成“描述符”参数。但我无法设计出一种方法让这个位直接在呼叫站点,理想情况下我可以做一些简单的事情,比如
ForEach(data) {
SomeClass().view(for: $0)
}
我被卡住了:(救命!
【问题讨论】:
标签: ios swift generics swiftui