Mac OS X Reference Library Apple Developer
Search

Associative References

You use associative references to simulate the addition of object instance variables to an existing class.

Associative references are only available in Mac OS X v10.6 and later.

Adding Storage Outside a Class Definition

Using associative references, you can add storage to an object without modifying the class declaration. This may be useful if you do not have access to the source code for the class, or if for binary-compatibility reasons you cannot alter the layout of the object.

Associations are based on a key, so for any object you can add as many associations as you want, each using a different key. An association can also ensure that the associated object remains valid for at least the lifetime of the source object (without the possibility of introducing uncollectible cycles in a garbage-collected environment).

Creating Associations

You use the Objective-C runtime function objc_setAssociatedObject to make an association between one object and another. The function takes four arguments: the source object, a key, the value, and an association policy constant. Of these, the key and the association policy merit further discussion.

The following example shows how you can establish an association between an array and a string.

Listing 7-1  Establishing an association between an array and a string

static char overviewKey;
 
NSArray *array = [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];
// For the purposes of illustration, use initWithFormat: to ensure the string can be deallocated
NSString *overview = [[NSString alloc] initWithFormat:@"%@", @"First three numbers"];
 
objc_setAssociatedObject(array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN);
 
[overview release];
// (1) overview valid
[array release];
// (2) overview invalid

At point (1), the string overview is still valid because the OBJC_ASSOCIATION_RETAIN policy specifies that the array retains the associated object. When the array is deallocated, however (at point 2), overview is released and so in this case also deallocated. If you try to, for example, log the value of overview, you generate a runtime exception.

Retrieving Associated Objects

You retrieve an associated object using the Objective-C runtime function objc_getAssociatedObject. Continuing the example shown in Listing 7-1, you could retrieve the overview from the array using the following line of code:

NSString *associatedObject = (NSString *)objc_getAssociatedObject(array, &overviewKey);

Breaking Associations

To break an association, you typically use objc_setAssociatedObject, passing nil as the value.

Continuing the example shown in Listing 7-1, you could break the association between the array and the string overview using the following line of code:

objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);

(Given that the associated object is being set to nil, the policy isn’t actually important.)

To break all associations for an object, you can use objc_removeAssociatedObjects. In general, however, you are discouraged from using this since this breaks all associations for all clients. You only use this function if you need to restore an object to “pristine condition.”

Complete Example

The following program combines the code samples from the preceding sections.

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
    static char overviewKey;
 
    NSArray *array = [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];
    // For the purposes of illustration, use initWithFormat: to ensure we get a
    // deallocatable string
    NSString *overview = [[NSString alloc] initWithFormat:@"%@", @"First three numbers"];
 
    objc_setAssociatedObject(array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN);
    [overview release];
 
    NSString *associatedObject = (NSString *)objc_getAssociatedObject(array, &overviewKey);
    NSLog(@"associatedObject: %@", associatedObject);
 
    objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);
    [array release];
 
    [pool drain];
    return 0;
}



Last updated: 2010-07-13

Did this document help you? Yes It's good, but... Not helpful...