33

I have created a custom Settings.app bundle using the standard root.plist approach for the iPhone. I'm wondering if there's a way to determine when the user changes those settings in my app...

pkamb
  • 33,281
  • 23
  • 160
  • 191
Ben
  • 16,124
  • 22
  • 77
  • 122

7 Answers7

45

You can listen for NSUSerDefaultsDidChange-notifications with this:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(defaultsChanged) name:NSUserDefaultsDidChangeNotification object:nil];

Whenever the NSUserDefaults changes, defaultsChanged will be called.

Don't forget to call [[NSNotificationCenter defaultCenter] removeObserver:self]; when you want to stop listening for these notifications (you should also do this when object gets deallocated).

Emil
  • 7,220
  • 17
  • 76
  • 135
  • ah ok, make sense. now my next question is, how can I determine which settings were changed? – Ben Oct 13 '10 at 21:21
  • 4
    +1. Typically you'd addObserver in `-init` (or `-application:didFinishLaunchingWithOptions:` for the app delegate) and removeObserver in `-dealloc`. This is easier than keeping track of how many times you've registered (if you addObserver twice, you get called twice each time the notification is posted, IIRC). – tc. Oct 13 '10 at 21:21
  • 3
    @Ben There is no real way to determine which settings were changed, but if you look for something specific, try storing the old version when the notifications gets run, then check against that the next time. – Emil Oct 13 '10 at 21:34
  • now I'm running into another problem. here's my flow: 1) log into app (causes - settings to be loaded, and copied (to compare later for changes) 2) exit app, go into settings, change setting 3) go back into my app, check settings and compare w/ old ones, but the new settings aren't noticed, even after calling 'synchronize' on the standardUserSettings object. – Ben Oct 13 '10 at 22:27
  • 3
    wow lovely, i just figured out that if you call synchronize once it doesn't work but call it twice & it does work. gotta love that – Ben Oct 13 '10 at 22:36
14

The syntax is for Swift 2. Using Swift you would do something like this to subscribe to changes for the NSUserDefaults :

NSNotificationCenter.defaultCenter().addObserver(self, selector: "defaultsChanged:", name: NSUserDefaultsDidChangeNotification, object: nil)

Then create the method like this :

func defaultsChanged(notification:NSNotification){
    if let defaults = notification.object as? NSUserDefaults {
       //get the value for key here
    }
}
Joseph
  • 5,793
  • 4
  • 34
  • 41
  • 4
    Syntax for Swift 3: `NotificationCenter.default.addObserver(self, selector: #selector(self.defaultsChanged), name: UserDefaults.didChangeNotification, object: nil)` – Kushal Ashok Jul 05 '17 at 22:54
  • 1
    Is there an elegant way to *just* watch changes from settings in under 50 lines of code and juggling arrays of keys with KVO? – Ryan Romanchuk Nov 23 '19 at 05:23
8

Register to receive NSUserDefaultsDidChangeNotification notifications. It's not obvious, but the iOS Application Programming Guide describes it as such:

Preferences that your application exposes through the Settings application are changed

Yunus Nedim Mehel
  • 12,089
  • 4
  • 50
  • 56
Kris Markel
  • 12,142
  • 3
  • 43
  • 40
8

SWIFT 4

Register observer in viewController,

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

Selector implementation

 @objc func settingChanged(notification: NSNotification) {
    if let defaults = notification.object as? UserDefaults {
        if defaults.bool(forKey: "enabled_preference") {
            print("enabled_preference set to ON")
        }
        else {
            print("enabled_preference set to OFF")
        }
    }
}
Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256
2

An example accessing an app specific Bool type setting with key "instantWeb":

func observeUserDefaults(notification: NSNotification) {
    print("Settings changed")
    if let defaults = notification.object as? NSUserDefaults {
        if defaults.valueForKey("instantWeb") as! Bool==true {
            print("Instant Web ON")
        }
    }
}
1

Listen to change in settings

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someMethod:) name:NSUserDefaultsDidChangeNotification object:nil];

Remember to remove the observer, once this view controller is no longer in memory.

itsji10dra
  • 4,603
  • 3
  • 39
  • 59
iosCurator
  • 4,356
  • 2
  • 21
  • 25
-3

In iOS10, try this:

UNUserNotificationCenter.current().getNotificationSettings { (settings) in
    // Your code here
}
piet.t
  • 11,718
  • 21
  • 43
  • 52
Keerthesh
  • 77
  • 8