如何正确子类化CABasicAnimation添加自定义属性?解决初始化报错
解决子类化CABasicAnimation的初始化与回调问题
错误原因分析
你遇到的Use of unimplemented initializer 'init()'错误,是因为调用CustomCABasicAnimation()无参初始化方法时,自定义类未实现该初始化器——你仅定义了带callBack参数的初始化方法,而父类CABasicAnimation的无参初始化器不会被自动继承(自定义指定初始化器后,系统默认初始化器会失效)。
此外还有隐藏问题:CAAnimation添加到图层时会被系统拷贝(遵循NSCopying协议),若不处理拷贝逻辑,拷贝后的动画实例会丢失callBack属性,导致回调无法触发。
正确实现代码
1. 自定义CABasicAnimation子类
class CustomCABasicAnimation: CABasicAnimation, CAAnimationDelegate { // 将callBack设为可选类型,支持无参初始化后赋值 var callBack: (() -> Void)? // 实现无参初始化器 override init() { super.init() self.delegate = self } // 带回调参数的便捷初始化器(可选,支持直接创建时传入回调) convenience init(callBack: @escaping () -> Void) { self.init() self.callBack = callBack } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 重写拷贝方法,保证自定义属性被复制 override func copy(with zone: NSZone? = nil) -> Any { let copy = super.copy(with: zone) as! CustomCABasicAnimation copy.callBack = self.callBack copy.delegate = copy // 拷贝后的实例需将代理设为自身 return copy } // 实现动画停止回调逻辑 func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { guard flag else { return } // 仅在动画正常完成时触发回调 callBack?() } }
2. 调用示例(匹配你的目标结构)
extension NSView { func fadeAnimation(callBack: @escaping () -> Void) { let animation = CustomCABasicAnimation() animation.callBack = callBack // 配置动画参数 animation.keyPath = "opacity" animation.duration = 2.0 animation.fromValue = 1.0 animation.toValue = 0.0 animation.timingFunction = CAMediaTimingFunction(name: .linear) animation.isRemovedOnCompletion = false animation.fillMode = .forwards self.layer?.add(animation, forKey: nil) } }
关键细节说明
- 初始化器处理:实现
override init()无参初始化器,同时将子类自身设为代理,确保回调能被正确触发;便捷初始化器为可选扩展,满足不同创建场景。 - 拷贝逻辑:重写
copy(with:)方法,手动复制callBack属性并绑定拷贝实例的代理,避免系统拷贝后丢失回调关联。 - 回调触发时机:在
animationDidStop中判断flag是否为true,仅在动画正常完成时执行回调,避免动画被提前终止时误触发。
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

