Dec 10, 2012
Some thoughts on NSCache and NSDictionary
I have to work on a new projects with multiple concurrency issues.
During debugging this application I discovered and interesting thing about NSCache: it looks like NSCache retains and autorelease objects before pass them out (but NSDictionary does not):
// A possible objectForKey: implementation:
- (id)objectForKey:(id)key {
id obj = [self _getObjectForKey:key];
return [[obj retain] autorelease];
}
Why?
Apple declares NSCache a threadsafe class.
Consider the following situation:
NSCache * cache = ...;
// Thread A:
NSString * cachedString = [cache objectForKey:key1]; // point A1
// do smth with a string:
NSLog(@"String value is %@", cachedString); // point A2
// Thread B:
[cache removeObjectForKey:key1]; // point B1
Consider the processor executes A1, then switches to B1 and returns to A2 after that.
In such a case we will have an invalid pointer to cachedString at point A2 (if we did not retain cachedString somewhere else).
But if objectForKey returns a retained-autoreleased value it is OK – the pointer is still valid (and it will remain valid until autorelease pool drain).
You may wish to retain-autorelease values while dealing with NSDictionary:
NSMutableDictionary * dict = ...;
// Thread A:
NSString * value = nil;
{ Lock lock(mutex);
value = [[[dict objectForKey:key1]retain]autorelease];
} // critical section ends
// do smth with a string:
NSLog(@"String value is %@", value);
// Thread B:
[dict removeObjectForKey:key1]; // point B1