#import <objc/runtime.h>

Objective-C developers are conditioned to be wary of whatever follows this ominous incantation. And for good reason: messing with the Objective-C runtime changes the very fabric of reality for all of the code that runs on it.

In the right hands, the functions of <objc/runtime.h> have the potential to add powerful new behavior to an application or framework, in ways that would otherwise not be possible. In the wrong hands, it drains the proverbial sanity meter of the code, and everything it may interact with (with terrifying side-effects).

Therefore, it is with great trepidation that we consider this Faustian bargain, and look at one of the subjects most-often requested by NSHipster readers: associated objects.

Associated Objects—or Associative References, as they were originally known—are a feature of the Objective-C 2.0 runtime, introduced in OS X Snow Leopard (available in iOS 4). The term refers to the following three C functions declared in <objc/runtime.h> , which allow objects to associate arbitrary values for keys at runtime:

objc_set Associated Object

objc_get Associated Object

objc_remove Associated Objects

Why is this useful? It allows developers to add custom properties to existing classes in categories, which is an otherwise notable shortcoming for Objective-C.

@interface NSObject ( Associated Object ) @property ( nonatomic , strong ) id associated Object ; @end @implementation NSObject ( Associated Object ) @dynamic associated Object ; - ( void ) set Associated Object :( id ) object { objc_set Associated Object ( self , @selector ( associated Object ), object , OBJC_ASSOCIATION_RETAIN_NONATOMIC ); } - ( id ) associated Object { return objc_get Associated Object ( self , @selector ( associated Object )); }

It is often recommended that they key be a static char —or better yet, the pointer to one. Basically, an arbitrary value that is guaranteed to be constant, unique, and scoped for use within getters and setters:

static char k Associated Object Key ; objc_get Associated Object ( self , & k Associated Object Key );

However, a much simpler solution exists: just use a selector.

Since SEL s are guaranteed to be unique and constant, you can use _cmd as the key for objc_set Associated Object() . #objective-c #snowleopard — Bill Bumgarner (@bbum) August 28, 2009

Associative Object Behaviors

Values can be associated onto objects according to the behaviors defined by the enumerated type objc_Association Policy :

Behavior @property Equivalent Description OBJC_ASSOCIATION_ASSIGN @property (assign) or @property (unsafe_unretained) Specifies a weak reference to the associated object. OBJC_ASSOCIATION_RETAIN_NONATOMIC @property (nonatomic, strong) Specifies a strong reference to the associated object, and that the association is not made atomically. OBJC_ASSOCIATION_COPY_NONATOMIC @property (nonatomic, copy) Specifies that the associated object is copied, and that the association is not made atomically. OBJC_ASSOCIATION_RETAIN @property (atomic, strong) Specifies a strong reference to the associated object, and that the association is made atomically. OBJC_ASSOCIATION_COPY @property (atomic, copy) Specifies that the associated object is copied, and that the association is made atomically.

Weak associations to objects made with OBJC_ASSOCIATION_ASSIGN are not zero weak references, but rather follow a behavior similar to unsafe_unretained , which means that one should be cautious when accessing weakly associated objects within an implementation.

According to the deallocation timeline described in WWDC 2011, Session 322 (~36:00), associated objects are erased surprisingly late in the object lifecycle — object_dispose() , which is invoked by NSObject -dealloc .

Removing Values

One may be tempted to call objc_remove Associated Objects() at some point in their foray into associated objects. However, as described in the documentation, it’s unlikely that you would have an occasion to invoke it yourself:

The main purpose of this function is to make it easy to return an object to a “pristine state”. You should not use this function for general removal of associations from objects, since it also removes associations that other clients may have added to the object. Typically you should use objc_setAssociatedObject with a nil value to clear an association.

Patterns

Adding private variables to facilitate implementation details

When extending the behavior of a built-in class, it may be necessary to keep track of additional state. This is the textbook use case for associated objects.

Adding public properties to configure category behavior.

Sometimes, it makes more sense to make category behavior more flexible with a property, than in a method parameter. In these situations, a public-facing property is an acceptable situation to use associated objects.

Creating an associated observer for KVO

When using KVO in a category implementation, it is recommended that a custom associated-object be used as an observer, rather than the object observing itself.

Storing an associated object, when the value is not needed

A common pattern for views is to create a convenience method that populates fields and attributes based on a model object or compound value. If that value does not need to be recalled later, it is acceptable, and indeed preferable, not to associate with that object.

Storing an associated object, when the value can be inferred

For example, one might be tempted to store a reference to a custom accessory view’s containing UITable View Cell , for use in table View:accessory Button Tapped For Row With Index Path: , when this can retrieved by calling cell For Row At Index Path: .

Using associated objects instead of X

…where X is any one the following:

Subclassing for when inheritance is a more reasonable fit than composition.

Target-Action for adding interaction events to responders.

Gesture Recognizers for any situations when target-action doesn’t suffice.

Delegation when behavior can be delegated to another object.

NSNotification & NSNotificationCenter for communicating events across a system in a loosely-coupled way.

Associated objects should be seen as a method of last resort, rather than a solution in search of a problem (and really, categories themselves really shouldn’t be at the top of the toolchain to begin with).

Like any clever trick, hack, or workaround, there is a natural tendency for one to actively seek out occasions to use it—especially just after learning about it. Do your best to understand and appreciate when it’s the right solution, and save yourself the embarrassment of being scornfully asked “why in the name of $DEITY” you decided to go with that solution.