iOS - Setobject VS. Synchronize

iOS - setObject vs. Synchronize

On iOS 7 and earlier:

When you call -setObject:forKey:, NSUserDefaults schedules a synchronize operation itself for roughly 10 seconds in the future. When that occurs, everything up to that point is saved to persistent storage. The idea here is that you can freely use the set and get methods without paying the significant performance cost of going out to disk every time.

On iOS 8, NSUserDefaults works differently, and the delay is a few milliseconds, rather than 10 seconds, so -synchronize is almost never useful.

On iOS 12, all remaining uses of -synchronize are unnecessary. Note that there may still be cases apps want to call it because they support iOS 11 and earlier.

iOS NSUserDefaults access before synchronize completion

Yes, your application can access the saved preferences before the synchronize happens, if it is saved before the read cycle happens during the same run session of the application. For accessing the information during subsequent app launches it is necessary that the synchronisation happens.

From the Apple docs: NSUserDefaults

NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. The synchronize method, which is automatically invoked at periodic intervals, keeps the in-memory cache in sync with a user’s defaults database.

The synchronize method writes any modifications to in-memory cache to the disk (plist file in Library/Preferences) and updates the unmodified in-memory cache to the latest on disk. This method gets invoked at periodic intervals, without the app getting notified.

From docs again: [NSUserDefaults synchronize]

Discussion
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.

In my experience, call the synchronize method explicitly when application is going to exit, this ensures that the latest preferences are available on next launch. However, I have also come across scenarios when application crashes before the synchronize happens so the pref are not stored. Your application must be able to handle these scenarios.

Additional

Use the NSUserDefaults to store minimal data, do not store huge data. Reason is, the app defaults are loaded during the app launch, if the data to load is huge then the app loading time increases and chances are that the app is killed by the Springboard.

NSUserDefaults not saved after synchronize

You have key and value reversed:

[defaults setObject:userID forKey:kArchivedUsername];

Credit to: Teja Nandamuri

What is the modern objective c syntax for NSUserDefault setObject?

Since it came up in comments, I thought I'd go ahead and elevate it to an answer so it doesn't get lost. The better code here would be:

NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
[ud setObject:self.date forKey:@"rankDate"];
[ud setInteger:self.date.people forKey:@"people"];

I've made several changes. First, rankDate makes no sense as the name of standardUserDefaults and is very misleading. Second, it uses setInteger:forKey: rather than messing around with NSNumber wrappers. There's no need for that. Finally, it gets rid of synchronize. That seldom does what you really meant, especially on iOS (it just waits).

That said, this whole object model is incredibly confusing. It seems "date" isn't a date, "people" isn't people, and you're saving the same data twice. But that's a separate issue. The main thing is that there's no proper application of "modern Objective-C" here. You shouldn't be using NSNumber (i.e. @(...)), and there's no subscripting on NSUserDefaults (i.e. ud[@"..."]).

(The existence of setInteger:forKey: and all the other specific set methods on NSUserDefaults I believe explains why it does not have subscripting. That would special-case objects, which would make the code inconsistent and encourage NSNumber wrapping when it isn't needed.)

NSUserDefaults synchronize-method

The purpose of [default synchronize]; is to make the user defaults get written on disk immediately. You don't need to call it explicitly, iOS already does it at appropriate moments. So you can remove that line. In fact, it's a performance problem if you call synchronize every time you set a default.

Prior to iOS 7, the user defaults were always synchronized when the application transitioned into background. As of iOS 7, that is no longer the case, so you might want to call synchronize in your app delegate's applicationDidEnterBackground: or register to the UIApplicationDidEnterBackgroundNotification notification to do that.

From the documentation for -[NSUserDefaults synchronize]:

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.



Related Topics



Leave a reply



Submit