3

The project I am working on has an extension that writes data to UserDefaults. Then in the containing app should the UI should get updated according to the changes. The problem is that UserDefaults.didChangeNotification does not get fired unless the screen comes from background. What could be the reason and is there a way to be fixed or another way to get the needed update?

Writing the data in the extension:

let sharedUserDefaults = UserDefaults(suiteName: Common.UserDefaultsSuite)
var receivedNotifications = sharedUserDefaults?.array(forKey: Common.ReceivedNotifications)
if receivedNotifications != nil {
    receivedNotifications?.append(aData)
} else {
    receivedNotifications = [aData]
}
sharedUserDefaults?.set(receivedNotifications, forKey: Common.ReceivedNotifications) 

Registering for the notification in the view controller:

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange), name: UserDefaults.didChangeNotification, object: nil)

}

And working with changed user defaults (that actually does not get called):

@objc func userDefaultsDidChange(_ notification: Notification) {

    print("User defaults did change")
    gatherReceivedNotifications()

}
surToTheW
  • 772
  • 2
  • 10
  • 34

2 Answers2

3

Still no idea why the other way doesn't work but the following works so it's a solution. As per suggested here I did the following:

override func viewDidLoad() {
    super.viewDidLoad()

    UserDefaults(suiteName: Common.UserDefaultsSuite)?.addObserver(self, forKeyPath: Common.ReceivedNotifications, options: .new, context: nil)

}

Then implemented observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?):

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == Common.ReceivedNotifications {
        gatherReceivedNotifications()
    }
}

It is fired immediately and only when a change to UserDefaults for the key Common.ReceivedNotifications is made.

surToTheW
  • 772
  • 2
  • 10
  • 34
0

The code #selector(userDefaultsDidChange) is means func userDefaultsDidChange() without parameter.

But you defined func userDefaultsDidChange(_ notification: Notification), it's have one parameter.

Next step:

Change #selector(userDefaultsDidChange) to #selector(userDefaultsDidChange(_:)) can fixed it.

Tuesleep
  • 119
  • 13
  • @LeonardoHammer Thank you for the response, I gave it a shot and there is no change. Still not firing the event. – surToTheW Jul 04 '18 at 12:25
  • 1
    Probably this: This notification isn't posted when changes are made outside the current process, or when ubiquitous defaults change. You can use key-value observing to register observers for specific keys of interest in order to be notified of all updates, regardless of whether changes are made within or outside the current process. from https://developer.apple.com/documentation/foundation/userdefaults/1408206-didchangenotification ie if you change the default from another process (like an extension) you won't see the change unless you observe the key as per the accepted answer – Red Nightingale Jun 15 '20 at 03:44