1

I have an application that downloads information from a web service and caches it in memory. Specifically, my singleton cache class contains an instance variable NSMutableDictionary *memoryDirectory which contains all of the cached data. The data in this cache can be redownloaded easily, so when I receive a UIApplicationDidReceiveMemoryWarningNotification I call a method to simply invoke

- (void) dumpCache:(NSNotification *)notification
{
    memoryDirectory = nil;
}

I’m a little worried about the thread safety here. (I’ll admit I don’t know much about threads in general, much less in Cocoa’s implementation.) The cache is a mutable dictionary whose values are mutable dictionaries, so there are two levels of keys to access data. When I write to the cache I do something like this:

- (void) addDataToCache:(NSData *)data
                 forKey:(NSString *)
                 subkey:(NSString *)subkey
{
    if (!memoryDirectory)
        memoryDirectory = [[NSMutableDictionary alloc] init];

    NSMutableDictionary *methodDictionary = [memoryDirectory objectForKey:key];
    if (!methodDictionary) {
        [memoryDirectory setObject:[NSMutableDictionary dictionary] forKey:key];
        methodDictionary = [memoryDirectory objectForKey:key];
    }

    [methodDictionary setObject:data forKey:subkey];
}

I’m worried that sometime in the middle of the process, dumpCache: is going to nil out the dictionary and I’m going to be left doing a bunch of setObject:forKey:s that don’t do anything. This isn’t fatal but you can imagine the problems that might come up if this happens while I’m reading the cache.

Is it sufficient to wrap all of my cache reads and writes in some kind of @synchronized block? If so, what should it look like? (And should my dumpCache: be similarly wrapped?) If not, how should I ensure that what I’m doing is safe?

bdesham
  • 15,430
  • 13
  • 79
  • 123
  • Anyway, your dumpCache: is wrong. It's not enough to nil out the cache. You rather want to release it and reallocate a new one, or simply setDictionary: to an empty dictionaryy –  Jan 24 '12 at 05:41
  • I’m using ARC, so I don’t think I can explicitly release it, but setting it to an empty dictionary is easy enough. That would also make if(!memoryDirectory) unnecessary, since it will always at least be initialized. – bdesham Jan 24 '12 at 05:51
  • You don't need to check it against not-nil. Sending messages to nil is legal. –  Jan 24 '12 at 05:55

1 Answers1

2

Instead of using an NSMutableDictionary, consider using NSCache, which is thread safe. See this answer for example usage. Good luck!

Community
  • 1
  • 1
Reed Olsen
  • 9,099
  • 4
  • 37
  • 47