According to the code below, ...
// Init a dictionary
NSMutableDictionary *dic = [NSMutableDictionary alloc] init];
[dic setObject:anObj forKey:@"key"]
...
// A : run on thread X
OBJ *obj = [dic objectForKey:@"key"];
[obj doSomething];
...
// B : run on thread Y
[dic removeObjectForKey:@"key"];
If A and B are run on different threads, X and Y, EXC_BAD_ACCESS
can occur, right ?.
Because :
-[NSDictionary objectForKey:]
doesn't retain and autorelease the returned value.-[NSMutableDictionary removeObjectForKey:]
does release the object.
[obj doSomething];
will crash if [dic removeObjectForKey:@"key"];
is executed first.
A question pops up :
How can we avoid this ?
My first idea is that to retain the return value of -[NSDictionary objectForKey:]
, but it is not enough.
Why ? Because of the 2 reasons above, there is a duration that the returned value is only retained by the dictionary. If B is executed in that duration, it will crash definitely.
// A : run on thread X
OBJ *obj = [[[dic objectForKey:@"key"] retain] autorelease];
[obj doSomething];
...
// B : run on thread Y
[dic removeObjectForKey:@"key"];
So, only retain doesn't work. RIP the 1st idea
The second idea is that to serialize them.
// A : run on thread X
@synchronized(dic) {
OBJ *obj = [[dic objectForKey:@"key"] retain] autorelease];
}
[obj doSomething];
...
// B : run on thread Y
@synchronized(dic) {
[dic removeObjectForKey:@"key"];
}
If I do it like this, it will work fine.
The 3rd idea is that over-retain all objects in the dictionary and release them when remove from the dictionary or dealloc the dictionary.
// Init a dictionary
NSMutableDictionary *dic = [NSMutableDictionary alloc] init];
[anObj retain];
[dic setObject:anObj forKey:@"key"]
...
// A : run on thread X
OBJ *obj = [dic objectForKey:@"key"];
[obj doSomething];
...
// B : run on thread Y
OBJ *obj = [dic objectForKey:@"key"];
[dic removeObjectForKey:@"key"];
[obj release];
Here are my questions :
- How can people in non-ARC world use NSMutableDictionary without facing
EXC_BAD_ACCESS
? - Did they always use single thread ?
- Did they always use lock or synchronization like I demonstrated above ?
- And also, in ARC world, can this situation happen ?
- Or my assumptions are all wrong ?