【问题标题】:KVO infinit loop with 2 way binding2路绑定的KVO无限循环
【发布时间】:2017-06-28 18:17:41
【问题描述】:

我有两节课。 A 类有 B 类,但 B 类不知道 A 类的存在

这两个类都可以被外部因素(例如服务或逻辑)改变

但我需要让两个类保持相同的值同步

由于A类知道B类,我可以在其值更改后直接赋值

为了让B 类知道A 类,我决定实现KVO,这样A 类会在B 类更改时得到通知

我的代码看起来像这样

class A : NSObject {
    var b : B

    @objc dynamic var anOtherString:String? {
        didSet{
            b.someString = self.anOtherString
        }
    }

    override init() {
        self.b = B()
        super.init()
        addObserver(self, forKeyPath: #keyPath(b.someString), options: [.old , .new], context: nil)
    }

    // MARK: - Key-Value Observing
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

        if keyPath == #keyPath(b.someString) {
            // Update Time Label
            anOtherString = b.someString
        }
    }

}


class B : NSObject {
    @objc dynamic var someString: String?
}

问题是我的代码处于无限循环中

因为每当我的班级B 发生更改时,它都会通知班级A,而当班级A 更新时,它会再次更改班级B 的值,从而创建一个新的通知等等...

我已经尝试分析Thread.callStackSymbols 以检测循环并停止它但没有成功。

【问题讨论】:

  • 你的真实代码做得更多吗?对于您发布的代码,A 类没有理由必须观察 B 类。当 b.someString 更改时,您在 A 类中所做的只是用相同的值更新 b.someString。没有任何理由。
  • 当然你可以添加一个检查新旧值是否相同。如果它们相同,则不要执行任何操作。
  • @maddy - 我想检查旧值和新值。但这是在一个非常复杂的应用程序中,在特定情况下不起作用,有必要为这些情况创建替代解决方案

标签: ios swift binding key-value-observing


【解决方案1】:

由于当 A 因 B 而更改时,您不能允许 A 更新 B,因此您可以有一个布尔变量来跟踪 A 是否需要更新 B。

class A : NSObject {
    var b : B
    var bChanged: Bool = false // Logic to track if B made a change

    @objc dynamic var anOtherString:String? {
        didSet{
            // If B did not make a change, then update B
            if !bChanged {
                b.someString = self.anOtherString

            // Otherwise set the flag
            }else {
                bChanged = false
            }
        }
    }

    override init() {
        self.b = B()
        super.init()
        addObserver(self, forKeyPath: #keyPath(b.someString), options: [.old , .new], context: nil)
    }

    // MARK: - Key-Value Observing
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

        if keyPath == #keyPath(b.someString) {
            // Update Time Label
            bChanged = true // B made a change
            anOtherString = b.someString
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 2013-07-03
    • 1970-01-01
    相关资源
    最近更新 更多