Associative References

If you’ve been developing with Objective-C for a while you know it’s powerful stuff. While it’s not as elegant looking as some languages, such as Ruby, it does have a rather impressive array of features that make it just flexible as new languages, such as Ruby.

One of the flexible features of Objective-C is Categories. Categories allow developers to snap on methods to classes they didn’t create and don’t have access to their source code. Beyond that, these methods become part of the class hierarchy.

One complaint that I’ve had with Categories is that you can’t add properties as part of the category snap on. Recently I wanted to extend UITextView so that it would be easier to take advantage of AttributesStrings. My first thought was to create a Category and initially it seemed I was on the right track. That was, until I realized that I wanted to have the UITextView keep track of default fonts. Default fonts mean properties and properties mean so long Category … or does it?

After building a subclass of UITextView, to do the things I want AND adding new properties, I wasn’t happy with the way thing looked. It’s not that the code wouldn’t do it’s job but it just didn’t feel as clean as it could be. I tried to improve my code by splitting off some capability into a Category.

As I wrote the Category it just felt right so I started trying to move the rest of my code into the category but still there were these properties. A little research on the net turned over something new, Associative References.

Associative References make it possible, like Categories, to attach (or associate) an object instance variables to an existing class and as the French would say “et voila” there you go, Categories with Properties.

Ok, so how do you make use of Associative References? First stop is to add properties to your Category:

@interface UITextView (Utilities)

@property (nonatomic, strong) UIFont *regularFont;

Now, Xcode will complain that since this is a category you’re going to have to implement the getter and setter for this property. So let’s get to implementing:

#import <objc/runtime.h>

static void *RegularFontKey;

@implementation UITextView (Utilities)

- (UIFont *)regularFont{
    return objc_getAssociatedObject(self, &RegularFontKey);
}

- (void)setRegularFont:(UIFont *)regularFont{
    objc_setAssociatedObject(self, &RegularFontKey, regularFont, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

Lines 7-9 and 11-13 are the methods that addresses Xcodes complaint. Pretty boiler plate. The magic happens on lines 8 and 12. Line 12 sets the value of the property and line 8 gets the value of the property. In both cases you’ll notice the use of the void pointer from line 3. This is a key that makes the association possible and it needs to be unique per property  and per class but not per property. This means that a developer simply has to replicate the pattern in line 3 per key.

In general, I would say simply replicate the pattern laid out in the code above to add properties to a category.

Happy Hunting

Leave a Reply

Your email address will not be published. Required fields are marked *