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.

Where U At? Holiday Server Release 6

Happy Holidays from team Where U At? We've been slaving away with Santa's helpers to bring this great release. Ok, perhaps Santa's helpers had something different to do this past week and didn't actually help as much as we're saying. With much fanfare here's what we changed:

Where U At? Server Release 6 (12/26/2010)

  1. Set location "grey area" from 50% to 200% to prevent triggering too many "your friend is near" push notifications.
  2. Fixed reset password to work without giving a message that phone or email is required.
  3. Changed an invitation to simply send a Facebook post, email or SMS and to not automatically create a friendship as this was causing confusion.
  4. Actually send an SMS when inviting with a phone number... Imagine that!
  5. Proximity alerts now alert the owner of a meetup when an invitee arrives.
And just in case you haven't installed our app yet you can download it from http://bit.ly/whereuat

    Friday, December 24, 2010

    Objective-C Immutable Example

    With Objective-C there is no such thing as truly immutable example as you can always get at the memory and manipulate it (it's just pointers and memory after all). We had a goal of creating an immutable contract for Objective-C but still leverage the @property notation to minimize the memory management errors. The usecase is that in XCode any code type ahead would only show the read only accessors so that we know not to attempt to write to a property. But, internally in the class we can use the synthesized writeable accessors.

    Here's an example of how we did it. First, define an interface in a usual manner, but set the properties to @property (readonly). Specify an initializer that takes all the methods.
    #import <foundation/foundation.h>
    
    @interface FooItem : NSObject
    
    
    @property (nonatomic, retain, readonly) NSString* name;
    @property (nonatomic, retain, readonly) NSNumber* count;
    - (id) initWithValues:(NSString*) givenName withCount:(NSNumber*) givenCount; @end
    Then in the implementation define a no name category that specifies the actual properties to be synthesized. These are done as readwrite so that the implementation itself has write accessors. In the initializer still continue to use the self accessors to have the benefits of runtime memory management.
    #import "FooItem.h"
    
    @interface FooItem ()
    
    @property (nonatomic, retain, readwrite) NSString* name;
    @property (nonatomic, retain, readwrite) NSNumber* count;
    
    @end
    
    @implementation FooItem
    
    @synthesize name;
    @synthesize count;
    
    - (id) initWithValues:(NSString*) givenName withCount:(NSNumber*) givenCount {
        self = [super init];
        if (self) {
            self.name = givenName;
            self.count = givenCount;
        }
     
        return self;
    }
    
    - (void) dealloc {
        self.name = nil;
        self.count = nil;
     
        [super dealloc];
    }
    
    @end
    
    Note, you could go to a true immutable implementation which would do a copy of the objects given in the initializer and specify copy on the @property. That seems an unnecessary amount of overhead for everyday use.