iosswiftperformancensuserdefaults

When and why should you use NSUserDefaults's synchronize() method?


So I've had a look at the apple documentation on the NSUserDefaults's synchronize() method. See below for reference:

https://developer.apple.com/reference/foundation/userdefaults/1414005-synchronize

The page currently reads:

Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.

However, what I still don't understand is when should this method be called? For example, should it be called every time the user changes the app's settings? Or should I just trust that the background api is going to handle that? And does the leaving of the view immediately after a settings change in memory result in that change being lost?

Also, when might a failure to call synchronize() result in user settings not getting changed correctly?

Furthermore, what is the cost (performance, memory or otherwise) of calling this method? I know it involves reading and writing from/to the disk but does that really take that much effort on phones?


Solution

  • There seems to be so much confusion about user defaults. Think of it this way. It's essentially the same as you having a global dictionary available throughout your app. If you add/edit/remove a key/value to the global dictionary, that change is immediately visible anywhere in your code. Since this dictionary is in memory, all would be lost when your app terminates if it wasn't persisted to a file. NSUserDefaults automatically persists the dictionary to a file every once in a while.

    The only reason there is a synchronize method is so your app can tell NSUserDefaults to persist the dictionary "now" instead of waiting for the automatic saving that will eventually happen.

    And the only reason you ever need to do that is because your app might be terminated (or crash) before the next automatic save.

    In my own apps, the only place I call synchronize is in the applicationDidEnterBackground delegate method. This is to ensure the latest unsaved changes are persisted in case the app is terminated while in the background.

    I think much of the confusion comes from debugging an app during development. It's not uncommon during development that you kill the app with the "stop" button in the debugger. And many times this happens before the most recent NSUserDefaults changes have been persisted. So I've developed the habit of putting my app in the background by pressing the Home button before killing the app in the debugger whenever I want to make sure the latest updates are persisted.

    Given the above summary, let's review your questions:

    should it be called every time the user changes the app's settings?

    No. As described above, any change is automatically available immediately.

    Or should I just trust that the background api is going to handle that?

    Yes, trust the automatic persistence with the exception of calling synchronize when your app enters the background.

    And does the leaving of the view immediately after a settings change in memory result in that change being lost?

    This has no effect. Once you add/edit/delete a key/value in NSUserDefaults, the change is made.

    Also, when might a failure to call synchronize() result in user settings not getting changed correctly?

    The only time a change can be lost is if your app is terminated before the latest changes have been persisted. Calling synchronize when your app enters the background solves most of these issues. The only remaining possible problem is if your app crashes. Any unsaved changes that have not yet been persisted will be lost. Fix your app so it doesn't crash.

    Furthermore, what is the cost (performance, memory or otherwise) of calling this method? I know it involves reading and writing from/to the disk but does that really take that much effort on phones?

    The automatic persistence is done in the background and it simply writes a dictionary to a plist file. It's very fast unless you are not following recommendations. It will be slower if you are misusing NSUserDefaults to store large amounts of data.