Reputation: 597
I'm using KVO for manual notifications, but why the code crashed for the reason:
Thread 1:EXC_BAD_ACCESS (code=2, address=0x7fff577bcfa8)" when click run?
Please see below the codes:
ChildrenViewController.swift
(class to be observed)
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
(the observer)
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)")
}
}
}
}
Upvotes: 1
Views: 571
Reputation: 3404
You are setting value of name
in it's own setter by this line:
self.setValue(value, forKey: "name")
Why can't do this:
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")
}
}
Upvotes: 2
Reputation: 2446
You added addObserver
in viewWillAppear
method, so it means you added it every time when your screen is show. For this case you need call removeObserver
in viewWillDisappear
method
override func viewWillDisappear(animated: Bool) {
self.child1.removeObserver(self, forKeyPath: "name")
self.child1.removeObserver(self, forKeyPath: "age")
super.viewWillDisappear(animated)
}
Upvotes: 0