observeValue called twice on UserDefaults

Viewed 561

My main view controller is added as observer for some key in UserDefault. But every time the value changed, observeValue is called twice.

The stacks are different for these two calls.

The first one is from frame #6: forEachObserver + 332 frame #7: -[CFPrefsSource didChangeValues:forKeys:count:] + 68 frame #8: -[CFPrefsSource setValues:forKeys:count:removeValuesForKeys:count:] + 340 frame #9: -[CFPrefsSource setValue:forKey:] + 56

The second one is from frame #6: forEachObserver + 332 frame #7: -[CFPrefsSource _notifyObserversOfChangeFromValuesForKeys:toValuesForKeys:] + 68 frame #8: __84-[CFPrefsSearchListSource asynchronouslyNotifyOfChangesFromDictionary:toDictionary:]_block_invoke_2 + 36

The only related post I found is from cocoa-dev mail list https://lists.apple.com/archives/cocoa-dev/2016/Nov/msg00084.html. It seems this issue appears from MacOS 10.12

Can someone provide more details on why it happens or how to suppress the duplicate messages?

A minimal example to reproduce:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        UserDefaults.standard.addObserver(
            self,
            forKeyPath: "test",
            options: .new,
            context: nil
        )

        UserDefaults.standard.set(true, forKey: "test")
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print("Observed: \(object ?? "None")")
    }
}
0 Answers
Related