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
How to Open Amazon App from Within My App
Xcode 9.3 - Nspredicate Bool Crash
Modifing One Variable from Another View Controller Swift
Increase the Width of Content View Programmatically in Swift
Why Can't I Call My Function with Gesturetaprecogniser
Calling Delegate Function from Appdelegate Not Working
iOS 10.3 - How to Change App Icon Programmatically
Exception: Cannot Manually Set the Delegate on a Uinavigationbar Managed by a Controller
Replace C Style For-Loop in Swift 2.2.1
Swift Parse - Local Datastore and Displaying Objects in a Tableview
Video Thumbnail Taking 10-15 Secs to Display
Fbsdk (New Facebook Sdk 4.0) Implementation Is Not Working for Login with Facebook
iOS Revoke Location Services Permission Programmatically
Aes 128 Message Decryption -- Swift, iOS
Swift Difference Between Var Arr:[String] = [] and Var Arr = [String]()
Swift 3 Filter Array of Dictionaries by String Value of Key in Dictionary