Disk Catching Protocol Buffers in iOS

There were a few times when we needed to persist Protocol Buffer objects retrieved from the Where U At? servers in order to reduce the frequency of GET calls per client (iPhone/iPad/iPod). You need to gauge your usage and determine when appropriate times are to cache, but for us, photos were an easy win.

If you haven't dabbled in Protocol Buffers for Objective-C, we highly recommend taking a look at:

 http://code.google.com/p/metasyntactic/wiki/ProtocolBuffers for starters.

By doing a bulk photos fetch (for every friend), and persisting to the local iOS documents cache directory, we can save an average of 5-8 calls per user per hour of usage. The following code demonstrates how to convert a Protocol Buffer object to an NSData stream for writing. We simply have these methods within a singleton Objective-C class:

 #define USER_CACHE_ALL_PHOTOS_PATH @"All_Photos.pb"

- (NSString*) cacheDir { NSArray *paths =

NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, Y ES);

if ([paths count] > 0) {

return [paths objectAtIndex:0];

         }

   return nil;

}

 - (void)writePhotos {

if (photos != nil) {

NSOutputStream* rawOutput = [[NSOutputStream outputStreamToMemory] retain]; PBCodedOutputStream* output =

[[PBCodedOutputStream streamWithOutputStream:rawOutput] retain];[photos writeToCodedOutputStream:output];[output flush];NSData* actualData = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryS

treamKey];NSString* pathToStorePhotos =

[[NSString [self cacheDir], USER_CACHE_ALL_PHOTOS_PATH] retain]; [pathToStorePhotos release];[output release];[rawOutput release];

       }

}

 - (Photos*)readPhotos {

 Photos* photosOnDisk = nil;

 NSString* pathToStorePhotos = [[NSString

   stringWithFormat:@"%@/%@",

[self cacheDir], USER_CACHE_ALL_PHOTOS_PATH] retain];

NSData *photoData = [[NSData dataWithContentsOfFile:pathToStorePhotos] retain]; if (photoData)

{

photosOnDisk = [[[[Photos builder]

}

 [photoData release]; [pathToStorePhotos release]; return [photosOnDisk autorelease];

}

 Hope you enjoy this little snippet. It can also be reused for all your objects that need long-term disk cache.