设置保护的内在怪异地扩展到了整个阶级吗? [英] Inner didSet protection bizarrely extends to the whole class?

查看:98
本文介绍了设置保护的内在怪异地扩展到了整个阶级吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

众所周知,didSet当然不会从didSet内部再次在同一对象上运行. (示例.)

It's well-known that, of course, didSet will not run on the same object again from inside a didSet. (example.)

但是.似乎:该限制不仅适用于该对象,而且可能适用于同一类的任何对象 .

However. It seems that: the restriction applies not only to that object, but to maybe any object of the same class.

以下是Playground的复制粘贴测试用例.

Here are copy-paste test cases for Playground.

class C {
    var Test: Bool = false {
        didSet {
            print("test.")
            for c in r {
                c.Test = true
            }
        }
    }
    var r:[C] = []
}
var a:C = C()
var b:C = C()
var c:C = C()
a.r = [b, c]
a.Test = false

不起作用!

class C {
    var Test2: Bool = false {
        didSet {
            print("test2.")
            global.Test2 = true
        }
    }
}
var global:C = C()
var a:C = C()
a.Test2 = false

不起作用!

  1. 这是Swift的错误吗?

  1. Is this a Swift bug?

如果不是,实际限制是什么?它不会运行任何从didSet开始的didSet(无论如何)?同一班级?同样的超一流?还是?

If not, what is the actual restriction? It won't run ANY didSet (whatsoever) that starts from a didSet?; the same identical class?; the same super class?; or?

这在doco中有何解释?

Where exactly is this explained in the doco?

WTF.需要知道……具体的限制是什么?

WTF. One needs to know ... what is the actual restriction specifically?

推荐答案

这是错误 SR- 419 .

从有关该错误的评论开始:

From the comment on the bug:

U.我们确实需要检查属性访问的基础是静态self.

从我的实验看来,只有在任何对象上设置相同的属性时,才会调用didSet观察器.如果您设置了任何其他属性(即使在同一对象上),那么观察者也会被正确调用.

and from my experiments it seems that the didSet observer is not invoked only if you set the same property on any object. If you set any other property (even on the same object), the observer is invoked correctly.

class A {
    var name: String
    var related: A?
    var property1: Int = 0 {
        didSet {
            print("\(name), setting property 1: \(property1)")

            self.property2 = 100 * property1
            related?.property1 = 10 * property1
            related?.property2 = 100 * property1
        }
    }
    var property2: Int = 0 {
        didSet {
            print("\(name), setting property 2: \(property2)")
        }
    }

    init(name: String) {
        self.name = name
    }
}

let a = A(name: "Base")
a.related = A(name: "Related")
a.property1 = 2

输出:

基本,设置属性1:2
基本,设置属性2:200
相关,设置属性2:200

Base, setting property 1: 2
Base, setting property 2: 200
Related, setting property 2: 200

预期输出应为:

基本,设置属性1:2
基本,设置属性2:200
相关的设置属性1:20
相关的设置属性2:2000
相关,设置属性2:200

Base, setting property 1: 2
Base, setting property 2: 200
Related, setting property 1: 20
Related, setting property 2: 2000
Related, setting property 2: 200

似乎您还需要直接从观察者中分配该属性 .输入其他功能(或观察者)后,观察者将再次开始工作:

It seems you also need to assign that property directly from the observer. Once you enter another function (or observer), the observers start working again:

var property1: Int = 0 {
    didSet {
        print("\(name), setting property 1: \(property1)")

        onSet()
    }
}

...    
func onSet() {
    self.property2 = 100 * property1
    related?.property1 = 10 * property1
    related?.property2 = 100 * property1
}

这是最好的解决方法.

另一种解决方法(感谢 @Hamish )是将嵌套的赋值包装到立即执行的闭包中:

Another workaround (thanks @Hamish) is to wrap nested assignments into an immediately executed closure:

var property1: Int = 0 {
    didSet {
       {
           self.property2 = 100 * property1
           related?.property1 = 10 * property1
           related?.property2 = 100 * property1
       }()
    }
}

根据关闭之前的代码,您可能必须将其包装在括号中或在前面的语句之后插入分号.

Depending on code before the closure, you might have to wrap it into parenthesis or insert a semicolon after the preceding statement.

这篇关于设置保护的内在怪异地扩展到了整个阶级吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆