Swift中能否将父类设为泛型参数实现统一继承UIViewController?
动态指定UIViewController父类的实现方案
你描述的泛型继承父类的语法确实在Swift中不被原生支持,下面是3种可以实现相同效果的常用技巧:
方案1:协议扩展(POP 推荐方案)
这个方案最符合Swift的语言设计,无需依赖Runtime,兼容纯Swift类。
实现逻辑:
- 先定义公共能力协议,给UIViewController添加协议的默认实现
- 需要使用该能力的UIViewController子类直接声明遵守协议即可
代码示例:
// 定义公共能力协议 protocol CommonViewControllerBehavior where Self: UIViewController { func setupCommonLogic() } // 给协议添加默认实现,把公共逻辑写在这里 extension CommonViewControllerBehavior { func setupCommonLogic() { // 原伪代码中viewDidLoad里的自定义逻辑写在这里 view.backgroundColor = .white print("公共逻辑执行") } } // 任意需要使用公共能力的VC,只要遵守协议,在对应生命周期调用方法即可 class CustomViewController: UIViewController, CommonViewControllerBehavior { override func viewDidLoad() { super.viewDidLoad() setupCommonLogic() // 一行注入公共逻辑 } }
如果需要批量给所有UIViewController注入能力,不需要每个类手动遵守,可以直接扩展UIViewController:
extension UIViewController: CommonViewControllerBehavior {}
方案2:Runtime 动态生成子类
如果完全不想修改原有VC的代码,可以利用OC Runtime动态创建指定父类的子类,注入公共逻辑:
import Foundation import UIKit func createViewControllerSubclass<T: UIViewController>(base: T.Type) -> T.Type? { let subclassName = "DynamicSubclass_\(NSStringFromClass(base))" guard let subclass = objc_allocateClassPair(base, subclassName, 0) as? T.Type else { return nil } // 重写viewDidLoad方法 let originalViewDidLoad = #selector(T.viewDidLoad) let originalImp = class_getMethodImplementation(base, originalViewDidLoad) typealias ViewDidLoadImp = @convention(c) (UIViewController, Selector) -> Void let newImp: @convention(block) (UIViewController) -> Void = { vc in // 先调用原父类的viewDidLoad unsafeBitCast(originalImp, to: ViewDidLoadImp.self)(vc, originalViewDidLoad) // 在这里添加自定义公共逻辑 print("动态注入的viewDidLoad逻辑") } class_addMethod(subclass, originalViewDidLoad, imp_implementationWithBlock(newImp), "v@:") objc_registerClassPair(subclass) return subclass } // 使用示例 let dynamicSubClass = createViewControllerSubclass(base: UIViewController.self) let vc = dynamicSubClass!.init()
方案3:视图控制器容器(装饰器模式)
如果需要对VC的展示逻辑做统一包装,推荐使用iOS原生的VC containment方案:
class CommonContainerViewController: UIViewController { private let childVC: UIViewController init(child: UIViewController) { self.childVC = child super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() // 公共逻辑写在这里 addChild(childVC) view.addSubview(childVC.view) childVC.view.frame = view.bounds childVC.didMove(toParent: self) } } // 使用示例 let originVC = MyOriginalViewController() let wrappedVC = CommonContainerViewController(child: originVC)
方案选型建议
- 优先选方案1,无黑盒逻辑、编译时安全、维护成本最低
- 只在测试场景、需要无侵入修改原有逻辑时选择方案2
- 需要统一包装UI层级、路由逻辑时选方案3
内容的提问来源于stack exchange,提问作者matt
相关产品推荐
相关产品推荐

