Search code examples
ioscrashnsuserdefaultsios9

NSUserDefaults setObject crashing in Thread


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


Solution

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