子类能否移除weak修饰符重写父类的存储属性?
关于子类重写父类weak存储属性的解决方案
这个问题其实是Swift属性重写里的一个常见限制——你没办法直接用存储属性重写父类的存储属性,哪怕只是想去掉weak关键字。不过我们可以用计算属性绕开这个限制,实现你要的效果。
为什么直接重写会报错?
Swift的语法规则明确规定:子类不能用存储属性重写父类的存储属性。不管父类的属性有没有weak、lazy这类修饰符,只要是存储属性,子类就不能用另一个存储属性来覆盖它。所以你写override var myVar : UILabel!这种存储属性重写的代码,必然会收到“Cannot override with a stored property”的错误。
解决方案:计算属性+子类内部强引用存储属性
要实现子类中让这个属性变成强引用,我们需要用计算属性重写父类的属性,同时在子类内部维护一个自己的强引用存储属性来持有实例。具体代码如下:
class Foo { weak var myVar: UILabel! } class Foo2: Foo { // 子类内部维护一个强引用的存储属性,用来持有UILabel实例 private var _strongMyVar: UILabel? override var myVar: UILabel! { get { // 返回子类自己持有的强引用实例,如果为空则 fallback 到父类的属性 return _strongMyVar ?? super.myVar } set { // 把新值存在子类的强引用属性里,确保实例不会被释放 _strongMyVar = newValue // 可选:同步给父类的myVar,保证父类能拿到这个值(如果父类有相关逻辑依赖它的话) super.myVar = newValue } } }
方案原理说明
- 计算属性可以合法重写父类的存储属性,这是Swift允许的语法。
- 子类内部的
_strongMyVar是强引用,当你给Foo2的myVar赋值时,这个属性会牢牢持有实例,避免了父类weak属性带来的自动释放问题。 - 同步给父类的
super.myVar是可选操作——如果你的父类代码不需要用到myVar的值,可以去掉这一步;但如果父类有依赖这个属性的逻辑,保持同步能避免出现不一致的情况。
额外注意事项
- 要保持重写的计算属性和父类属性的类型一致(这里都是
UILabel!隐式解包可选类型),否则会出现类型不匹配的错误。 - 如果你的业务场景中不需要父类的
myVar属性再有值,可以在set方法里不用同步给super.myVar,只赋值给子类自己的_strongMyVar即可。
内容的提问来源于stack exchange,提问作者Domenico Taffuri
相关产品推荐
相关产品推荐

