Swift/UIKit中如何为不同视图类型复用基类逻辑?
解决方案:抽离共享逻辑+组合模式
针对UIView和UIStackView这类不同基类视图的逻辑复用问题,核心思路是把重复的核心逻辑(如layoutSubviews内的处理、协议实现)抽离到独立的工具类中,再通过组合的方式让不同视图子类持有这个工具类,从而避免复制粘贴和多份维护。
方案1:独立逻辑处理类(最直接的组合实现)
把所有共享代码封装到一个独立的PlasticLogicHandler类中,让UIView和UIStackView的子类分别持有该类实例,在对应的生命周期方法中调用handler的逻辑:
// 抽离所有共享逻辑的处理类 class PlasticLogicHandler: SomeProto { // 原Plastic类中的初始化/通用配置逻辑 func performCommonSetup() { // 这里写原来blah的具体实现 } // 原layoutSubviews中的核心逻辑,通过参数接收视图实例 func performLayoutSubviews(for view: UIView) { // 这里写原来layoutSubviews里blah的具体实现,比如子视图布局、样式调整等 } // 实现SomeProto协议的所有方法 func protoMethod() { // 协议方法的共享实现 } } // UIView子类:复用handler逻辑 class Plastic: UIView, SomeProto { private let logicHandler = PlasticLogicHandler() override init(frame: CGRect) { super.init(frame: frame) logicHandler.performCommonSetup() } required init?(coder: NSCoder) { super.init(coder: coder) logicHandler.performCommonSetup() } override func layoutSubviews() { super.layoutSubviews() logicHandler.performLayoutSubviews(for: self) } // 转发协议方法到handler func protoMethod() { logicHandler.protoMethod() } } // UIStackView子类:完全复用同一套handler逻辑 class PlasticForStackViews: UIStackView, SomeProto { private let logicHandler = PlasticLogicHandler() override init(frame: CGRect) { super.init(frame: frame) logicHandler.performCommonSetup() } required init?(coder: NSCoder) { super.init(coder: coder) logicHandler.performCommonSetup() } override func layoutSubviews() { super.layoutSubviews() logicHandler.performLayoutSubviews(for: self) } // 转发协议方法到handler func protoMethod() { logicHandler.protoMethod() } }
这种方式下,所有核心逻辑只在PlasticLogicHandler中维护,修改一次即可同步到所有视图子类。如果需要访问视图的私有属性,可以通过闭包、属性传递或者给handler添加弱引用的视图对象来实现交互。
方案2:协议扩展+关联类型(进一步精简子类代码)
如果想减少子类中的重复代码,可以结合协议扩展+关联类型,把调用逻辑封装到协议中:
protocol PlasticCompatible: UIView, SomeProto { associatedtype ViewType: UIView var logicHandler: PlasticLogicHandler { get } } extension PlasticCompatible { // 协议扩展封装通用调用逻辑 func setupPlastic() { logicHandler.performCommonSetup() } func layoutPlasticSubviews() { logicHandler.performLayoutSubviews(for: self as! ViewType) } // 协议方法默认转发到handler func protoMethod() { logicHandler.protoMethod() } } // UIView子类 class Plastic: UIView, PlasticCompatible { typealias ViewType = UIView let logicHandler = PlasticLogicHandler() override init(frame: CGRect) { super.init(frame: frame) setupPlastic() } required init?(coder: NSCoder) { super.init(coder: coder) setupPlastic() } override func layoutSubviews() { super.layoutSubviews() layoutPlasticSubviews() } } // UIStackView子类 class PlasticForStackViews: UIStackView, PlasticCompatible { typealias ViewType = UIStackView let logicHandler = PlasticLogicHandler() override init(frame: CGRect) { super.init(frame: frame) setupPlastic() } required init?(coder: NSCoder) { super.init(coder: coder) setupPlastic() } override func layoutSubviews() { super.layoutSubviews() layoutPlasticSubviews() } }
这个方案通过协议扩展把重复的调用逻辑统一封装,子类只需要声明关联类型、持有handler,以及重写layoutSubviews调用封装好的方法即可,代码更简洁。
内容的提问来源于stack exchange,提问作者Fattie
相关产品推荐
相关产品推荐

