0

I'm trying to call a function after the user defaults change. Below is the code I'm using.

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    //Watch user default changes
    UserDefaults.standard.addObserver(self, forKeyPath: "arrayA", options: NSKeyValueObservingOptions.new, context: nil)
    UserDefaults.standard.addObserver(self, forKeyPath: "arrayB", options: NSKeyValueObservingOptions.new, context: nil)
}

func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutableRawPointer) {
    filterItems()
    self.tableView.reloadData()
}

deinit {
    UserDefaults.standard.removeObserver(self, forKeyPath: "arrayA")
    UserDefaults.standard.removeObserver(self, forKeyPath: "arrayB")
}

The code was inspired from this answer. I have modified it a bit for Swift 3.

When doing an action that would update the user defaults the app crashes and the following is printed to the console.

An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.

Basically when the key arrayA or arrayB are changed I want it to call filterItems() and self.tableView.reloadData(). It could also call those on any user defaults change but that would be less efficient.

Community
  • 1
  • 1
Charlie Fish
  • 18,491
  • 19
  • 86
  • 179
  • I think you need an @objc declaration on observeValueForKeyPath. – Ewan Mellor Feb 26 '17 at 09:11
  • Using `@objc func observeValueForKeyPath` gives the same error. Unless I don't understand what you mean. – Charlie Fish Feb 26 '17 at 09:13
  • are you sure you override the corret func ? override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { print(change) } – Xingou Feb 26 '17 at 09:44
  • @Xingou What do you mean? – Charlie Fish Feb 26 '17 at 09:44
  • @Xingou At first glance it looks like that works. I ran into another error so not 100% sure yet. Feel free to post an answer and if it works I will up vote and accept. – Charlie Fish Feb 26 '17 at 09:48
  • I have tried your code but does not get me any error, neither can't catch the observer, in fact observeValueForKeyPath function never called. – Maryam Fekri Feb 26 '17 at 10:06

2 Answers2

0

You have used the wrong method. Try replace it with:

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        filterItems()
        self.tableView.reloadData()
    }

Please notice the keyword override. Because observeValue(forKeyPath:of:change:context:) is a method inherited from NSObject. When you write down func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutableRawPointer) without it and the complier didn't complain for that, that's a sign that you've typed wrong.

liuyaodong
  • 2,547
  • 18
  • 31
0
     /** 
      this func is not the kvo func, 
     first : there is no "override" keyword.
     second: in swift3.0, the name is not correct。 it should be
         override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print(change)
    }
*/
     func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutableRawPointer) {
            filterItems()
            self.tableView.reloadData()
        }
Xingou
  • 1,141
  • 1
  • 10
  • 20