Search code examples
objective-ciosthread-safetygrand-central-dispatchatomic

Do you need your property to be Atomic, when using multiple threads and only getters?


Do you need your property to be Atomic, when using multiple threads and only getters?

Before I perform a segue, to a given ViewController, I set an instance variable.

That property, will be accessed from multiple threads (Getters only). Here's the code I'm using. Being executed from my tableView CellForRowAtIndexPath method.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    Day *aDay = [[[self days]  objectAtIndex:indexPath.section] objectAtIndex: indexPath.row];

    NSDictionary * data = [OperationsManager workTimeAndAmountForDay: aDay];

    NSString *workTime  = [data objectForKey:@"Work Time"];
    NSString *amount    = [data objectForKey:@"Amount"];

    NSString *textLabel = [NSString stringWithFormat:@"%d - H: %@ $: %@", [[aDay day_] integerValue], workTime, amount];

    dispatch_async(dispatch_get_main_queue(), ^{

        [[cell textLabel] setFont: [UIFont systemFontOfSize: 24.0]];
        [[cell textLabel] setText: textLabel];

        [cell setNeedsLayout];

    });

});

If I do these on one thread only. No GCD. There are NO erros. But if I do this while using GCD, I usually get something like this,

2012-08-30 13:05:52.027 Work Clock[17236:707] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'statement is still active'
*** First throw call stack:
(0x36a1188f 0x32e28259 0x352c93dd 0x352c8c87 0x3536c951 0x352d8b1f 0x352d0f73 0x35376dd5 0x352e2d1b 0x352e2247 0x352e1d5b 0x352e1c0b 0xc921f 0xc6fed 0x34c7f5cf 0x34c7f55f 0x34c4d495 0x34c42225 0x34c41763 0x34be5f37 0x369701fb 0x32083aa5 0x320836bd 0x32087843 0x3208757f 0x3207f4b9 0x369e5b1b 0x369e3d57 0x369e40b1 0x369674a5 0x3696736d 0x34b2e439 0x34c10cd5 0xbff55 0xbfef0)
terminate called throwing an exception2012-08-30 13:05:52.032 Work Clock[17236:1b03] *** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x2be320 <x-coredata://E4D2B2E1-B3D9-4358-810B-0FDE7A679A16/Day/p1>''
*** First throw call stack:
(0x36a1188f 0x32e28259 0x352e24f3 0x352e1d5b 0x352e1c0b 0xc95c9 0xc7395 0x37438c59 0x374447bb 0x32f59dfb 0x32f59cd0)
terminate called throwing an exception(lldb) 

I also have this method,

 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

It calls to some of the same properties. Sometimes the error happens there, but I only get Assembly code. I'm unable to replicate the error at this time.

One note,

My call to,

[OperationsManager workTimeAndAmountForDay: aDay];

Is a Class method, defined in my OperationsManager class. It has NO class properties whatsoever.

+(NSDictionary *)workTimeAndAmountForDay:(Day *)aDay;

So, If I'm using only getters when using multiple threads on my VC, and my Class method has no class properties.

Why do I keep getting these errors? Also, they are really hard to replicate! There is some "randomness" feel to it.

Any help is most appreciated!

I could just stop using GCD. And the errors go away. But user experience when scrolling decreases immensely.

Thank you in advance.

Nuno

Also, these are Core Data objects I'm accessing. Don't know if that helps? Also only one context. But then again. I'm only reading objects. Not saving or changing the objects state.


Solution

  • About atomic, read bbum's post at:

    http://www.friday.com/bbum/2008/01/13/objectivce-c-atomic-properties-threading-andor-custom-settergetter/

    When you look at the crash, it's CoreData related. See ...

    *** Terminating app due to uncaught exception
    'NSObjectInaccessibleException', reason: 'CoreData
    could not fulfill a fault for '0x2be320
    <x-coredata://E4D2B2E1-B3D9-4358-810B-0FDE7A679A16/Day/p1>''
    

    ... how do you access CoreData objects, contexts, ... from multiple threads? Did you read this article:

    http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/coredata/Articles/cdConcurrency.html%23//apple_ref/doc/uid/TP40003385-SW1