7

I know that documentation says that it is, and i know that this subject was already under discussion but I have an interesting stack result and I cant conclude anything else but that [NSUserDefaults standardUserDefaults] is not threadsafe. So I will post my crash log and hope that somebody sees something that I can't...

Crashed Thread

    ... 
    libdispatch.dylib 0x3ab53d67 _dispatch_client_callout + 23
    libdispatch.dylib 0x3ab65e73 _dispatch_barrier_sync_f_invoke + 27
    CoreFoundation 0x302b470d CFPreferencesAppSynchronize + 265       
    Foundation 0x30151b01 -[NSUserDefaults(NSUserDefaults) synchronize] + 25
    MyApp 0x0009df8b -[AppDelegate applicationDidEnterBackground:] (AppDelegate.m:178)
    ...
    MyApp 0x0005344b main (main.m:17)
    MyApp 0x000533f8 start + 40

some other thread

    ...
    CoreFoundation 0x302bc13f _CFXPreferencesSetValue + 107
    CoreFoundation 0x302bc039 CFPreferencesSetAppValue + 41
    Foundation 0x30c76935 -[NSUserDefaults(NSUserDefaults) setObject:forKey:] + 61
    MyApp 0x000b2e9d -[AppData parserDidEndDocument:] (AppData.m:1013)
   ...

Parts of the stack have been cut out and substituted with "..." cause its just too long and irrelevant for the subject. App crashes with message:

* Collection <__NSDictionaryM: 0x15a04ae0> was mutated while being enumerated. ....

Code: AppDelegate: -> crached thread...

    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
        [[NSUserDefaults standardUserDefaults] synchronize];
    }

MyClass: ->second thread:

    -(void)parserDidEndDocument:(NSXMLParser *)parser {
    ...
        [[NSUserDefaults standardUserDefaults] setObject:arr forKey:@"savedStations"];
        [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"lastUpdateDate"];
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"alreadyLoaded"];
    ...
    }

I have this crash in couple of other cases, it always includes some writing to user defaults in one thread and synchronizeing in other thread that crashes.. If anyone has some other explanation I would be very greatfull...

Wain
  • 118,658
  • 15
  • 128
  • 151
AntonijoDev
  • 1,317
  • 14
  • 29
  • Well if that "mutated while being enumerated" error was in the user defaults code then I would say that it's not thread safe. – trojanfoe Oct 21 '13 at 09:48
  • 2
    You have to call `synchronise` after every change on `NSUserDefaults` and from your code, the second thread is not calling it. – danypata Oct 21 '13 at 09:52
  • 1
    @danypata Why do you have to do that? – trojanfoe Oct 21 '13 at 09:52
  • 2
    hmmm, I tried that before, I called synchronise after every write to user defaults, it resulted in much more crashes so I removed the synchronise calls, and to be honest calling synchronise like U suggest doesn't make much sense cause purpose of synchronise is to dump content on disc, and iOs handles that for U periodically. Thats why my only call is in applicationDidEnterBackground method as documentation suggests... – AntonijoDev Oct 21 '13 at 10:01
  • Is you arr mutable, and do you modify it later? – Nickolay Olshevsky Oct 21 '13 at 10:03
  • @trojanfoe You have to call `synchronise` in order to `save` the changes, otherwise your might have inconsistent data, the system will periodically call `synchronise` but you should call it whenever you change something. – danypata Oct 21 '13 at 10:04
  • Yes, and yes.. Think we R on something here... But stack does'n show that it breaks while mutating object, and if it did I still don't see the problem. I write somethin in user defaults and continue to .... hmmm, maybe U R right, should I make a copy (non mutable array) and dump it to user defaults not the original mutable object? – AntonijoDev Oct 21 '13 at 10:08
  • and danypata the data will not be inconsistent it just wont be written on the disc (what could cause problems if the app crashes and U try to reload data...) but U will still work with consistent data that is written in your memory... – AntonijoDev Oct 21 '13 at 10:51
  • danypata is incorrect about when and why to call synchronize. Synchronization has no effect at all on in-memory state unless on-disk state has changed. – Catfish_Man Oct 29 '13 at 18:11
  • 1
    Could you post the full crash log? The snipped out bits are making it difficult to diagnose. – Catfish_Man Oct 29 '13 at 18:17
  • The use of `dispatch_barrier_sync` would actually imply some thought has gone into thread safety. Bu as per Catfish_Man's comment, you've given us barely any information to go on here. – Tommy May 09 '14 at 15:00
  • The problem might happen because of `arr`, which I assume a mutable collection. Foundation mutable collections are not thread safe, and if you want them to be so, you have to write your own version. To prove this (or not) try either remove writing `arr` or make it immutable. – Yevhen Dubinin Nov 21 '14 at 00:08

2 Answers2

2

The NSUserDefaults class is thread-safe.

(c) https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/index.html

Nekto
  • 17,837
  • 1
  • 55
  • 65
-8

nsuserdefaults in not thread safe . Please check apple documentation if it not discuss about thread safe for any ios terms then it is not thread safe....

  • 1
    As per the comment on the other answer, the documentation says the exact opposite of what you claim. See https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Classes/NSUserDefaults_Class/Reference/Reference.html and read the final sentence of the Overview. – Tommy May 09 '14 at 15:01
  • He answered it on Christmas. Cut him some slack for his bad mood. – Jameson Feb 20 '16 at 19:03