Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

idelovski

macrumors regular
Original poster
Sep 11, 2008
235
0
When I started creating my caching class I was sure I'll use it always on the main thread but it turns out I need it in multiple threads because UIScrollView in tiled mode draws the tiles in background threads. So now I need my cache to be thread safe.

I had to solve two problems: One, mutable array/dictionary holding cached images, and two, returned objects could dissapear while being used in another thread.

Am I doing this right?

Code:
- (UIImage *)cachedImageForAddress:(NSString *)imgAddress
{
   UIImage  *retImage = nil;
   
   @synchronized(self)  {
      retImage = [self.imageDictionary objectForKey:imgAddress];
   }
   
   return ([[retImage retain] autorelease]);
}

Code:
- (BOOL)cacheImage:(UIImage *)newImage forAddress:(NSString *)imgAddress
{
   BOOL  retVal = YES;
      
   @synchronized(self)  {
      
      if (![self.imgDicKeys containsObject:imgAddress])  {
         [self.imageDictionary setObject:newImage forKey:imgAddress];
         [self.imgDicKeys addObject:imgAddress];

         // See if thre's too many
         
         [self trimImageDictionary:self.imageDictionary
                          withKeys:self.imgDicKeys
                         toMaxSize:kMaxImagesInCache];
      }
      else  if (![self.imageDictionary objectForKey:imgAddress])
         NSLog (@"Inconsistant image cache!");
      else
         retVal = NO;
   }
   
   return (retVal);
}
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
There's a race condition in your getter. The returned value could be invalidated on another thread between the time you get it from the dictionary and when it's retained. I think you need to retain it inside the @synchronized block.

I don't understand what the keys array is for.
 

idelovski

macrumors regular
Original poster
Sep 11, 2008
235
0
There's a race condition in your getter. The returned value could be invalidated on another thread between the time you get it from the dictionary and when it's retained. I think you need to retain it inside the @synchronized block.

Oh, thanks for the tip. Now it looks obvious. ;)

I don't understand what the keys array is for.

I wasn't sure if allKeys property of the dictionary would always have the oldest element at zero index so I created my own array. Plus, in few methods I compare counts of objects in dictionary and array just to make sure there wasn't some sort of a mixup.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.