Swift:覆盖didSet会导致递归

当覆盖一个属性的didSet观察者会导致递归,为什么?
class TwiceInt {
    var value:Int  = 0 {
        didSet {
            value *= 2
        }
    }
}

class QuadInt : TwiceInt {
    override var value:Int {
        didSet {
            value *= 4
        }
    }
}

let t = TwiceInt()
t.value = 5 // this works fine


let q = QuadInt()
q.value = 5 // this ends up in recursion

如果我更新QuadInt

class QuadInt : TwiceInt {
    override var value:Int {
        didSet {
            super.value *= 4
        }
    }
}

q.value = 5 // q.value = 80

所以我猜这个电话是这样的:

value = 5
QuadInt:didSet ( value *= 4 )
value = 20
TwiceInt:didSet ( value *= 2 )
value = 40
TwiceInt:didSet ( value *= 2 )
value = 80

这或多或少是在黑暗中拍摄.有没有关于物业更新会发生什么的文件

你不能覆盖didSet,这不是一个普通的方法.实际上你没有覆盖didSet,你自己覆盖了属性.

didSet的作品像观察者一样工作,只是因为你将自己的观察者设置在一个继承的属性上,并不意味着任何其他观察者自动注册.所以你的超类的观察者完全不受这个影响,因此这两个didSet方法都将被调用到最后.

现在,如果您在自己的didSet观察器中更改值,则不会导致递归,因为Swift运行时足够聪明,以了解在执行此操作后,doSet实现将更改其自己的观察属性不会被再次调用.运行时知道当前正在执行的是什么didSet方法,如果变量在此方法返回之前更改,则不会再执行该方法.这个检查似乎不能跨越超类.

所以* = 4导致调用超类观察器,它设置* = 2,并且导致再次调用子类观察器,这将再次设置* = 4,导致再次调用超类观察者…和等等.

通过明确使用超级,你打破了这个循环,因为现在你没有设置你的被覆盖的属性,而是继承的超级属性,你并没有真正观察超级属性,你只是观察自己的覆盖的属性.

在一些语言中,您可以遇到与覆盖方法类似的问题,其中典型的解决方案也是在其中一个调用中显式地使用super.

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...