Sunday, December 26, 2010

Disk Caching 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, YES);
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:NSStreamDataWrittenToMemoryStreamKey];
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] mergeFromData:photoData] build] retain];
}
[photoData release];
[pathToStorePhotos release];
return [photosOnDisk autorelease];
}

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

1 comment:

  1. Restock Machines can break after the fourth assured reroll with a 50% probability for every subsequent reroll that ought to've been successful. Leaving the room afterward after which reentering resets Scapular, permitting for further donations using Soul Hearts. Repeating this course of after each Scapular activation allows Isaac to gather cash from the Blood Donation Machine until it breaks. Scapular no longer reactivates when using any well being donation mechanic whereas altering 1xbet rooms. Is held, there is a 50% probability to spawn an extra random coronary heart.

    ReplyDelete