Tuesday, June 28, 2011

Adopting an Objective-C Protocol Privately in the Implementation File

I continue to be surprised by the syntactic constructions allowed in Objective-C and the Coca/Cocoa Touch frameworks for iOS and Mac OS X.

iTimeZone for iOS, my world clock calculator app, has relied on the UIDatePicker control since it first shipped on July 15, 2008. The results haven't always been optimal. I've filed any number of bugs with Apple documenting how the control can get confused and show the wrong date & time. Sometimes they've been fixed, other times, like now, it takes such a long time it really reflects negatively on my app.

I've finally had it with this control. I've started reimplementing UIDatePicker as TGDatePicker. My goal is to be API compatible and eventually release this as an open source project so others can benefit.

So of course I started by looking at the UIDatePicker.h header in the iOS 4.3 SDK. The docs state and the header shows UIDatePicker manages a private UIPickerView to show its UI. But UIPickerView uses delegate and data source protocols to configure itself, but they're not adopted in the public header!

UIKIT_CLASS_AVAILABLE(2_0) @interface UIDatePicker : UIControl <NSCoding>
{
...
}
...
@end

I've never adopted a protocol outside of the header before, and I wanted to be as close in my implementation as possible to UIDatePicker, so the only other thing I could thing of is to adopt the protocols in the implementation file, like this:

#import "TGDatePicker.h"

@interface TGDatePicker () <UIPickerViewDataSource>

@end

@implementation TGDatePicker
...
@end

And it works! I can't think of a reason why Apple wanted to do this. It doesn't seem like adopted protocols are top secret information. I probably won't ever use this outside of this special case, but now I know just in case.