Kasper Munck

Adding Properties to Objective-C Categories

Categories, Properties and Ivars

Sometimes, subclassing causes unneccessary overhead (or is even discouraged by Apple, such as in the case of NSArray or NSDictionary). Especially if you need no more than a few extra properties. A category appears as a simpler solution, however, adding properties to a category is prohibited. Doing so causes one of the following errors, depending on which version of Xcode you are using:

No auto synthesis (before Xcode 4.4)

@synthesize not allowed in a category's implementation.

Auto synthesis

Property 'myProperty' requires method 'myProperty/setMyProperty' to be defined [...] 

Manually implementing a getter for the property could be the solution. Consider an NSManagedObject subclass with NSString properties for given an family name, respectively. It is not unline that you would provide a property for getting the full name:

// in the interface file
@property (readonly, nonatomic) NSString *fullName;

// in the implementation file
- (NSString *)fullName {
    return [NSString stringWithFormat:@"%@ %@", self.givenName, self.familyName)];
}

But, creating a setter is not as simple as creating a getter. An ivar for storing the value is required, and adding an ivar to a category will also result in an error:

Instance variables may not be placed in categories.  

This is due to the fact that it is impossible to guarantee a unique ivar. This could potentially lead to a situation where setting a new value for property A causes the value of property B to change too, because of clashing ivars.

Luckily, the Objective-C runtime has a feature called associated objects, which will […] simulate the addition of object instance variables to an existing class. This blog post at Techpaa explains associated objects in details. In short, you will have to provide an object to associate the "ivar" with, a unique key by which it is identified, and a socalled association policy. This policy must obey the characteristics of the property you add (that is, atomicity, memory management etc.):

MyManagedObject+Additions.h

@property (strong, nonatomic) NSString *test;

MyManagedObject+Additions.m

NSString const *key = @"my.very.unique.key";

- (void)setTest:(NSString *)test
{
    objc_setAssociatedObject(self, &key, test, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)test
{
    return objc_getAssociatedObject(self, &key);
}

Updates

12/03/2012

A great article about associated objects / references is now available at the Carbon Emitter blog.

11/12/2012

The article Advanced categories with associated objects by Krysztof Zablocki digs a little deeper with categories and associated objects. Absolutely worth a read.

[ property category objective-c ]