Swift中如何通过泛型向视图控制器注入通用数据?
Swift中如何通过泛型向视图控制器注入通用数据?
我来帮你梳理下这个问题哈,你现在的核心问题是Coordinator和Navigable两个协议的关联类型没对齐,代码里还有几处泛型使用的冲突问题,咱们一步步来解决:
先拆解你当前代码的核心问题
Navigable协议把关联类型固定死了:你用where T == AppData直接限定了所有遵循该协议的VC的data类型只能是AppData,但你的AppCoordinator的关联类型是String,类型完全不兼容,自然没法赋值。start方法的局部泛型冲突:你在start方法里重新声明了局部泛型<T>,这和Coordinator协议的associatedtype T是两个完全不同的类型,导致赋值时编译器无法匹配类型。- 关联类型约束方式错误:你想让
Coordinator的T和Navigable的T关联,但直接写associatedtype T: Navigable.T是不合法的——Swift不允许直接引用另一个协议的关联类型,必须通过where子句或者具体类型来约束。
修正后的完整代码方案
咱们重新设计两个协议的关联关系,保证类型安全的同时保留灵活性:
1. 重构Navigable协议
先去掉对关联类型的硬约束,让每个遵循协议的VC可以自定义data的类型:
protocol Navigable { // 把T改成Data是为了避免和Coordinator的关联类型混淆,你也可以继续用T associatedtype Data var data: Data? { get set } }
2. 重构Coordinator协议
用where子句约束start方法接收的Navigable对象,保证它的Data类型和Coordinator的关联类型完全一致:
protocol Coordinator { associatedtype Data var navigationController: UINavigationController { get } var data: Data? { get } // 用where子句约束:VC的Data类型必须和Coordinator的Data类型匹配 func start(viewController: some Navigable) where Navigable.Data == Data }
3. 修正AppCoordinator实现
去掉局部泛型,直接使用协议的关联类型,保证类型统一:
class AppCoordinator: Coordinator { // 指定当前Coordinator的Data类型为String typealias Data = String var data: Data? let navigationController: UINavigationController init(data: Data? = nil, navigationController: UINavigationController) { self.data = data self.navigationController = navigationController } // 这里的viewController已经被where子句约束,Data类型必然是String,和当前Coordinator的data类型匹配 func start(viewController: some Navigable) where Navigable.Data == Data { var mutableVC = viewController mutableVC.data = self.data } }
4. 调整WelcomeViewController实现
现在你可以让VC自定义data的类型,比如保持原来的AppData:
enum AppData { case coordinatorData } class WelcomeViewController: UIViewController, Navigable { // 自定义当前VC的data类型为AppData var data: AppData? var appCoordinator: (any Coordinator)? override func viewDidLoad() { super.viewDidLoad() setUp() } private func setUp() { // 如果要给这个VC注入数据,你需要用对应Data类型的Coordinator(比如下面的AppDataCoordinator) // appCoordinator?.start(viewController: self) } }
5. 适配AppData类型的协调器(可选)
如果需要给WelcomeViewController这类使用AppData的VC注入数据,你可以再实现一个对应类型的Coordinator:
class AppDataCoordinator: Coordinator { typealias Data = AppData var data: Data? let navigationController: UINavigationController init(data: Data? = nil, navigationController: UINavigationController) { self.data = data self.navigationController = navigationController } func start(viewController: some Navigable) where Navigable.Data == Data { var mutableVC = viewController mutableVC.data = self.data } }
额外的灵活性扩展
如果需要给关联类型加通用约束(比如要求Data必须遵循Equatable),可以直接在协议里加:
// 给Navigable的Data加约束 protocol Navigable where Data: Equatable { associatedtype Data var data: Data? { get set } } // 给Coordinator的Data加约束 protocol Coordinator where Data: Equatable { associatedtype Data // ... 其他内容 }
这样就完美解决了你之前遇到的类型匹配问题,同时保留了泛型的灵活性,不同的协调器可以对应不同的VC数据类型,实现安全的依赖注入。
备注:内容来源于stack exchange,提问作者Asaad Jaber
相关产品推荐
相关产品推荐

