为什么 KVO 的 var setter 崩溃了 (swift 2.2)?

why the setter of var for KVO crashed (swift 2.2)?

我正在使用 KVO 进行手动通知,但为什么代码崩溃的原因是:

Thread 1:EXC_BAD_ACCESS (code=2, address=0x7fff577bcfa8)" when click run?

请看下面的代码:

ChildrenViewController.swift(class待观察)

import UIKit
class ChildrenViewController: UIViewController {

dynamic var name: String? {
    get {
        return ""
    }

    set {
        willChangeValueForKey("name")
        guard let value = newValue else {return}
        self.setValue(value, forKey: "name") //crashed here!SAID "Thread 1:EXC_BAD_ACCESS (code=2, address=0x7fff577bcfa8)"
        didChangeValueForKey("name")
    }

}

dynamic var age = 0

var child: ChildrenViewController?

override class func automaticallyNotifiesObserversForKey(key: String) -> Bool {
    if key == "name" {
        return false
    }
    return super.automaticallyNotifiesObserversForKey(key)
}

}

ViewController.swift(观察者)

import UIKit

private var child1Context = 1

class ViewController: UIViewController {

var child1 = ChildrenViewController()

override func viewDidLoad() {
    super.viewDidLoad()

    self.child1.setValue("George", forKey: "name")
    self.child1.setValue(15, forKey: "age")
}

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    child1.addObserver(self, forKeyPath: "name", options: [.New,.Old], context: &child1Context)
    child1.addObserver(self, forKeyPath: "age", options: [.New, .Old], context: &child1Context)

    self.child1.name = "Michael" //set the name String
    self.child1.setValue(20, forKey: "age")
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)

    self.child1.removeObserver(self, forKeyPath: "name")
    self.child1.removeObserver(self, forKeyPath: "age")
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &child1Context {
        if keyPath == "name" {
            print("The name of FIRST has been changed, \(change)")
        }
        if keyPath == "age" {
            print("The age of FIRST has been changed, \(change)")
        }
    }               
    }

}

您在viewWillAppear方法中添加了addObserver,这意味着您在每次显示屏幕时都添加了它。对于这种情况,您需要在 viewWillDisappear 方法

中调用 removeObserver
override func viewWillDisappear(animated: Bool) {
    self.child1.removeObserver(self, forKeyPath: "name")
    self.child1.removeObserver(self, forKeyPath: "age")
    super.viewWillDisappear(animated)
}

您正在通过此行在 它自己的 setter 中设置 name 的值:

self.setValue(value, forKey: "name")

为什么不能这样做:

private var _name: String?//create private variable to hold value
dynamic var name: String? {
    get {
        return _name
    }

    set {
        willChangeValueForKey("name")
        guard let value = newValue else {return}
        _name = value
        didChangeValueForKey("name")
    }
}