12

I let the user make changes to their settings in the settings area of the iphone. During the next network sync i'd like to send the user changes to the server. But only if the changes are made.

But how do I know when the user has made a change within the settings area?

If I can, I'd like to avoid an option of always sending the information regardless if changed or not or getting the info from the server first and updating if different from the user defaults.

Is there a nice and elegant way of resolving this problem? Thank you for your help!

A week later and no answers... Is this question too hard or it doesn't make any sense at all?

san
  • 133
  • 1
  • 6

4 Answers4

18

Ah silly me! Here we go with an elegant way. Search for AppPrefs in the Apple Documentation within XCode and it'll show an example app which does exactly what you want to do. Just compile and run! It makes use of the NSUserDefaultsDidChangeNotification.

This is the code being used to register an observer:

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

Old answer:

It doesn't look like as if you could get a modification date out of the NSUserDefaults. So far I only can think of this way:

NSUserDefaults *previousDefaults = [someInstance previousUserDefaults];
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];

if([previousDefaults isEqualToDictionary:currentDefaults]) 
{
    [someOtherInstance sendModifiedUserDefaultsToServerWithDefaults:currentDefaults];
    [yetAnotherInstance saveModified]
}

You have to save the user defaults yourself as dictionary to disk when the app is launched the first time: your default values. Then, everytime the app is opened you compare those two dictionaries. If they

Nick Weaver
  • 47,228
  • 12
  • 98
  • 108
  • Hm.What makes me think that there is a better way is the fact that when you change your network settings on your iphone, it automatically tries to find and connect to it. This must mean that the user setting change has triggered an action. This would be a nice solution for me too. How they do this? – san Apr 02 '11 at 21:27
  • Here you go, an elegant and simple solution to the problem. – Nick Weaver Apr 02 '11 at 22:48
  • Oh yeah! This is great. But this triggers any change to the settings.Is there a way to act only on specific property change? – san Apr 03 '11 at 02:44
  • I think we are at the bottom of possibilities here. Please look at the NSUserDefaults class reference, it didn't reveal anything more useful to me. But if you find a way, please let us know here. – Nick Weaver Apr 03 '11 at 07:32
  • @Will I don't think so. Anyways, the userdefaults are per sandbox and should therefore be only changeable by the app itself. – Nick Weaver May 23 '14 at 06:53
2

It's not that the question is too hard, it's just that there's not a simple way to do what you're asking. NSUserDefaults doesn't record a "last modified" date for each app's settings, at least as far as I can tell, so if the user changes some settings using the Settings app, there's not a good way to detect that other than to look at all the settings.

If you really need to do this, I think your best bet is to read the settings that you're interested in syncing into some data structure and calculating some sort of hash or checksum based on that structure. Compare that value to the value that you calculated the last time the app ran, and sync with the server if it's different. You can store that value in NSUserDefaults if you want, but make sure that you don't include it in the calculation.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • Thanks Caleb.I do not want to make my solution too complicated.I am surprised that there was no need for something like this and that there is nothing in the library to support the idea,e.g., react to a change in the user settings. – san Apr 02 '11 at 21:30
  • Usually, an application doesn't care whether its preferences have changed recently -- it reads them from the defaults system whenever it needs them anyway, so if something has changed, the app automatically gets the new value. Also, NSUserDefaults comes from MacOS X, and in that context the user is supposed to be able to delete the app's preference file with no ill effects; the app should just fall back to its built-in defaults. Even on iOS, I wouldn't store critical information in the defaults system. – Caleb Apr 03 '11 at 00:30
0

Swift

Observe for changes and call a method on change:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(updateStateFromSettingsBundle),
    name: UserDefaults.didChangeNotification,
    object: nil
)
@objc func updateStateFromSettingsBundle() {}
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
  • You're still using `ObjC` here, since you're referring to an `@objc`-function. – Boothosh81 Aug 22 '22 at 21:40
  • Using `ObjC` does not turn the Swift code into Objective-C :) it means it is visible by objective-c runtime. The `NotificationCenter` class inherits from `NSObject` which is an objective-c class on the other hand ;) @Boothosh81 – Mojtaba Hosseini Aug 26 '22 at 09:57
0

Only Swift

You could also use only Swift if you want to:

NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: OperationQueue.main) { notification in
    // Do something
}
Boothosh81
  • 387
  • 1
  • 5
  • 24