Swift中能否实现动态泛型,匹配带关联类型协议的视图与数据类型调用?
问题原因
报错是因为带关联类型的协议无法直接作为类型使用,你将视图存储为Any类型后,编译期无法判断其是否遵守Base协议,也无法匹配关联类型M的泛型约束,因此无法直接调用泛型的update方法。这类动态类型匹配的需求在Swift中完全可以实现,有两种常用实现方案:
方案1:类型擦除(推荐,可拓展性强)
通过类型擦除包装器抹掉Base协议的关联类型约束,内部自动做类型校验,不需要修改原有协议和视图实现:
// 类型擦除包装器 struct AnyBase: Base { typealias M = Any private let _update: (Any) -> Void var data: Any init<C: Base>(_ base: C) { self.data = base.data _update = { data in // 内部自动校验类型是否匹配 guard let data = data as? C.M else { return } var mutableBase = base mutableBase.update(data: data) } } func update(data: Any) { _update(data) } } // 原有视图和协议不需要修改 protocol Base { associatedtype M var data:M { get set } func update(data:M) } class ViewA : Base { var data: String = "" func update(data: String) {} } class ViewB : Base { var data: Int = 2 func update(data: Int) {} } // 数组改为存储AnyBase类型 var dataArr : [Any] = ["1",2] var viewArr : [AnyBase] = [AnyBase(ViewA()), AnyBase(ViewB())] func updatData() { for i in 0..<2 { let view = viewArr[i] let data = dataArr[i] // 直接调用即可,类型不匹配会自动跳过 view.update(data: data) } }
该方案优势为后续新增任意遵守Base协议的视图,不需要修改调用逻辑,直接往数组里加AnyBase(新视图实例)即可。
方案2:运行时类型判断(适合视图数量少的场景)
如果遵循Base的视图数量不多,可以直接在遍历的时候做动态类型转换匹配,不需要新增类型:
func updatData() { for i in 0..<2 { let view = viewArr[i] // 注意你原有代码此处为笔误,大写I未定义,需要改为小写i let data = dataArr[i] if let viewA = view as? ViewA, let strData = data as? String { viewA.update(data: strData) } else if let viewB = view as? ViewB, let intData = data as? Int { viewB.update(data: intData) } } }
该方案劣势为每新增一种视图就要多加一个判断分支,维护成本较高。
内容的提问来源于stack exchange,提问作者chdo
相关产品推荐
相关产品推荐

