Understanding Xcode crash message and @synchronized directive

317 views Asked by At

Trying to write some code that uses iCloudKit singleton in addition to a global variables singleton to share variables and processes across multiple method calls, potentially from multiple iPads. And I have two questions in one.

Code crashes with this message right now.

2015-06-09 18:31:18.879 iBeacons Demo[277:24157] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSDictionaryM: 0x17024fdb0> was mutated while being enumerated.'

*** First throw call stack:

(0x184a742d8 0x1960340e4 0x184a73c8c 0x100024b0c 0x185975f9c 0x184a2c240 0x184a2b4e4 0x184a29594 0x1849552d4 0x18e0336fc 0x18951afac 0x10005eacc 0x1966b2a08)

libc++abi.dylib: terminating with uncaught exception of type NSException

Which as I understand it is an attempt by two methods to change the value in a shared instance of a mutable dictionary object. Somewhat new to OOC, equally new to programming within multiple threaded environments and xCode and I have a stupid question.

How can I trace which NSMutableDictionary object 0x17024fdb0 is referring too here?

And assuming I find it could/would the potential fix be to make its property declaration atomic like this, together with using the @synchronized directive.

So I have ...

property (retain, atomic) NSDictionary blah 

And

@synchronized(self) {
  // do something quickly
}
2

There are 2 answers

1
user3069232 On BEST ANSWER

Très Bon,

Your both right, although in fairness to all Tommy reply was the one that lead me to the fix.

for (NSString *student in studentNClass) {
if ([descriptions containsObject:student] ) {
    [studentNClass removeObjectForKey:student];
} else {
    [self addBeacon2Carousel:student];
    //singleBeaconsFound++;
    self.beaconsFound.text = [NSString stringWithFormat:@"%d",singleBeaconsFound];;
}

After Tommy..

for (NSString *student in [studentNClass allKeys]) {
    if ([descriptions containsObject:student] ) {
            [studentNClass removeObjectForKey:student];
    } else {
        [self addBeacon2Carousel:student];
        //singleBeaconsFound++;
        self.beaconsFound.text = [NSString stringWithFormat:@"%d",singleBeaconsFound];;
    }
}

THANK YOU!

0
Rob On

The typical source of this problem is simply that you're iterating through an array (e.g. a for loop or enumerateObjectsWithBlock or something like that) and try to add or remove objects while still iterating through the array. This can happen in the simplest, single-threaded code, and is unrelated to synchronizing multi-threaded code.

Obviously, if you're writing multi-threaded code you should synchronize the array, too, regardless, but it's probably not the problem here. The issue is likely just mutating the array while still iterating through the array in a for loop.


In your answers, you suggest that you want to remove all dictionary key/value pairs whose keys are present in another array. You can certainly use allKeys pattern suggested by Tommy. Or, in this case, using removeObjectsForKeys is probably easiet:

[students removeObjectsForKeys:descriptions];