I´m doing some stuff in the background. I do also try to write an object to the standard user defaults. Since iOS 9 it is crashing.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// calling some methods in the background
// also save a value to the user defaults
NSDate *aDate = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:aDate forKey:@"date"]; // <-- crash: EXC_BAD_ACCESS
});
I cannot find the problem. aDate is not nil. I also tried to perform setObject: on the main thread (from the background thread), but with the same result.
The crash is sporadic! What I´m doing wrong?
Here is the stack trace:
Crashed: com.apple.root.background-qos EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x0000000000000010
Thread : Crashed: com.apple.root.background-qos 0 libobjc.A.dylib
0x0000000199b0dbd0 objc_msgSend + 16 1 Foundation
0x0000000185ea1eb4 -[NSObject(NSKeyValueObserverNotification) willChangeValueForKey:] + 324 2 CoreFoundation
0x0000000185090994 _CFPreferencesSetValueWithContainer + 168 3 Foundation 0x0000000185eb9138 -[NSUserDefaults(NSUserDefaults) setObject:forKey:] + 56 4 AIR 0x00000001000f201c -[ServerSyncAgent syncUnsyncedEntities] (ServerSyncAgent.m:212) 5 libdispatch.dylib
0x000000019a2e97b0 _dispatch_call_block_and_release + 24 6 libdispatch.dylib 0x000000019a2e9770 _dispatch_client_callout + 16 7 libdispatch.dylib 0x000000019a2f7bb0 _dispatch_root_queue_drain + 2140 8 libdispatch.dylib 0x000000019a2f734c _dispatch_worker_thread3 + 112 9 libsystem_pthread.dylib 0x000000019a4fd478 _pthread_wqthread + 1092
From Apple's documentation:
The NSUserDefaults class is thread-safe.
The posted code is fine. Your error is elsewhere.
Edit: The stack points out the source of your bug:
Somewhere else in your code you (or some 3rd party library) are adding a KVO observer to [NSUserDefaults standardUserDefaults]
. Yet, NSUserDefaults
is not KVO compliant, so you can't add observers.
If there's need to react on changes to user defaults you have to use NSNotificationCenter
and register for NSUserDefaultsDidChangeNotification
.
2nd Edit: Not sure when this changed but in modern iOS and macOS NSUserDefaults
is Key-Value observable. The same documentation as linked above now clearly states:
You can use key-value observing to register observers for specific keys of interest in order to be notified of all updates to a local defaults database. For more details, see Key-Value Observing Programming Guide.