One of the features added to Objective-C 2.0 is Class Extensions.
If you have feature requests or bugs, http://bugreport.apple.com/ is your friend!
There has been a bit of confusion about their functionality and purpose.
First, a bit of background. One of the great strengths of Objective-C is the very sharp division between interface and implementation.
Not only can you declare a public interface to a class — the set of methods that clients of the class can use — but you can also declare varying degrees of private interface ranging from “stuff for my framework” through to “stuff only to be used in the implementation of this subset of methods of the class”.
Class extensions were designed to solve two problems. The first was to enable to compiler to better validate the private interfaces a class might have and the second was to solve a subtle, but gnarly, problem with properties (another feature added to Objective-C 2.0).
A class extension is declared just like a category, but without a name:
@interface MyClass () @end
The declarations found within the class extension directly extend the declarations found in the class’s primary
@interface. In a limited context, the declarations in a class extension can override declarations found in the primary interface.
Better Validation of Private Interfaces
When implementing a class, it is common to have a set of methods that only appear in the class’s
@implementation. Often, they are spread around the
@implementation and generally appear just above whatever method first uses the private method (if they were to appear below, the compiler will warn).
Eventually, this becomes unwieldy and the developer will capture the private method’s declarations into a category declaration at the top of the implementation file. Something like:
@interface MyClass (SuperSecretInternalSauce) - (void) doMyPrivateThing; - (BOOL) canMyPrivateThingEatThis: (OtherClass *) aThing; @end @implementation MyClass ... @end
These methods are typically not implemented in a corresponding
@implementation MycClass (SuperSecretInternalSauce) implementation block. Nor should they need to be!
The resulting problem is that the compiler will not check to make sure you have implemented all of the methods declared in that category. Nor will it catch, say, spelling errors in the method declarations in the implementation.
This is because a category with no corresponding implementation is an informal protocol in Objective-C. It is a set of method declarations that can optionally be implemented, often on a subclass of the class with the category declaration.
Because a class extension effectively extends the class’s primary interface, changing the above declaration to the following makes the declared methods have the same requirements as methods declared in the class’s oft public primary interface.
@interface MyClass () - (void) doMyPrivateThing; - (BOOL) canMyPrivateThingEatThis: (OtherClass *) aThing; @end @implementation MyClass ... @end
That is, the compiler will complain if the class’s @implementation does not contain implementations of the methods declared in the extension.
Public Readonly, Private Readwrite Properties
When designing properties, one goal was to not make them fairly robust. To these ends, it was decided that property declarations in categories, synthesis in particular, would be limited in functionality or prohibited entirely.
Aside: The reason synthesis was prohibited in categories was because synthesis requires storage and there was no way of declaring storage in a category efficiently and it wasn’t deemed acceptable to allow a category to synthesize methods that would then diddle the class’s ivars directly. Too fragile and ugly.
However, it was also obviously desirable to be able to declare a property that was publicly
readonly, but whose implementation was
readwrite for internal-to-the-class-or-framework purposes.
One additional requirement is that the synthesis such properties must always be able to synthesize both the setter and getter naturally and precisely. Specifically, when declaring a property as atomic, there is no way the developer can correctly manually write only 1/2 of the getter setter pair; the locking infrastructure is not exposed and, thus, there is no way to guarantee atomicity in such a situation.
Class extensions addressed this problem elegantly.
Specifically, you can declare a property like:
@interface MyClass : NSObject @property(readonly) NSView *targetView; @end
And, then, in the implementation file:
@interface MyClass() @property(readwrite) NSView *targetView; @end @implementation MyClass @synthesize targetView; @end
End result? A property that is publicly readonly, but privately readwrite without opening properties up to all of the fun fragility associated with categories.