3

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")")
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Liteye
  • 2,761
  • 1
  • 16
  • 16
  • iOS or macOS or both? How do you register the observer? A [mcve] would help others to reproduce the problem. – Martin R Jul 23 '17 at 15:28
  • Both. I can reproduce it in iOS 10.3.2 and macOS 10.12.5. But it works correctly in playground – Liteye Jul 23 '17 at 16:02
  • 1
    I do not know the answer, but I can confirm your observation. It seems that `UserDefaults.standard.set()` always causes a callback call, followed by another callback call if the value actually changed. – Martin R Jul 23 '17 at 16:22
  • 1
    It is a bug, and fixed in iOS 11/macOS 10.13, see https://stackoverflow.com/a/45464568/1187415. – Martin R Sep 14 '17 at 18:58

0 Answers0