Skip to content

Provides support for associated objects using zeroing weak references

License

Notifications You must be signed in to change notification settings

jodyhagins/WJHAssocObj

Repository files navigation

WJHAssocObj.framework

GitHub version Carthage compatible GitHub license

This is a very simple framework composed of C functions that extend the behavior of objc_setAssociatedObject and its counterparts. Some folks see C APIs as anathema, so I have also included a category on NSObject that provides the same capabilities.

Documentation

Documentation is provided in two forms. HTML documentation can be found in the Documentation/html directory. An apple docset is also already prepared in Documentation/docset. HTML documentation is also available on the project wiki.

The provided docset can be manually installed and integrated with Xcode. Also, the Xcode project includes a Documentation target that will build and install the docset from source. The generation script requires that appledoc be installed and in your PATH.

Motivation

The main drawback of the existing API is that it does not provide support for zeroing weak pointers. In addition, with ARC lots of ugly casts are necessary for even simple use cases. Thus, this library provides zeroing weak pointer support, and also makes it easier to associate both objects and native integral/pointer types.

See this blog post if you are interested in more details.

Installation

Carthage is the recommended way to install WJHAssocObj. Add the following to your Cartfile:

    github "jodyhagins/WJHAssocObj"

For manual installation, I recommend adding the project as a subproject to your project or workspace and adding the framework as a target dependency.

Usage

When using these functions, keep in mind these points (which, by the way, are the same as when using objc_setAssociatedObject).

  • The key is a void pointer, and should be unique. Do not use raw C-strings, as they are not guaranteed to be coalesced into a unique string. I recommend using the address of a static object, as it is guaranteed to be unique through the lifetime of the program. You can use the address of a function or a selector as well.

  • The first parameter is the object that "holds" the association.

  • You can only have one associated object per unique key. If you create an association with the same key as an existing association, the previous association will be removed.

  • The atomically parameter has the same meaning as atomic on property declarations.

Example

As an example, let’s pretend that we are adding several properties to an arbitrary category on NSObject, a prime use case for associated objects. The interface declaration may look like this.

@interface NSObject (Foo)
    @property (atomic, strong) id strongObject;
    @property (weak) id weakObject;
    @property (nonatomic, copy) id copiedObject;
    @property void* rawPointer;
    @property unsigned unsignedInteger;
@end

And the implementation could possibly look like this. I am using Appledoc to generate the documentation and it does not support C functions (but the generated documentation looks much better than that generated by either doxygen or headerdoc). Thus, the example uses the ObjC API.

@implementation NSObject(Foo)

#define kStrongKey (@selector(strongObject))
WJHAssociatedKey(kStrongKey);
- (id)strongObject {
    return [self wjh_associatedObjectWithKey:kStrongKey];
}
- (void)setStrongObject:(id)strongObject {
    [self wjh_associateStrongly:strongObject withKey:kStrongKey atomically:YES];
}

#define kWeakKey (@selector(weakObject))
- (id)weakObject {
    return [self wjh_associatedObjectWithKey:kWeakKey];
}
- (void)setWeakObject:(id)weakObject {
    [self wjh_associateWeakly:weakObject withKey:kWeakKey atomically:YES];
}

#define kCopyKey (@selector(copiedObject))
- (id)copiedObject {
    return [self wjh_associatedObjectWithKey:kCopyKey];
}
- (void)setCopiedObject:(id)objectToCopy {
    [self wjh_associateCopy:objectToCopy withKey:kCopyKey atomically:NO];
}

#define kPointerKey (@selector(rawPointer))
- (void*)rawPointer {
    return [self wjh_associatedPointerWithKey:kPointerKey];
}
- (void)setRawPointer:(void *)rawPointer {
    [self wjh_associatePointer:rawPointer withKey:kPointerKey];
}

#define kIntegerKey (@selector(unsignedInteger))
- (unsigned)unsignedInteger {
    return (unsigned)[self wjh_associatedIntegerWithKey:kIntegerKey];
}
- (void)setUnsignedInteger:(unsigned int)unsignedInteger {
    [self wjh_associateInteger:(intptr_t)unsignedInteger withKey:kIntegerKey];
}

@end

Notes

You use either WJHAssociateStrongly, WJHAssociateCopy, or WJHAssociateWeakly to create associations to objects. Objects must be fetched with WJHGetAssociatedObject. Or, using the ObjC API, that would be [NSObject(WJHAssocObj) wjh_associateStrongly:withKey:atomically:], [NSObject(WJHAssocObj) wjh_associateCopy:withKey:atomically:], or [NSObject(WJHAssocObj) wjh_associateWeakly:withKey:atomically:] to create associations to objects and [NSObject(WJHAssocObj) wjh_associatedObjectWithKey:] to fetch associated objects.

Similarly, you use WJHAssociatePointer and WJHAssociateInteger for associating non-objects, and they are to be fetched with WJHGetAssociatedPointer and WJHGetAssociatedInteger (though, technically, those two can be interchanged). Using tha ObjC API, that would be [NSObject(WJHAssocObj) wjh_associatePointer:withKey:] and [NSObject(WJHAssocObj) wjh_associateInteger:withKey:] to the create the associations and [NSObject(WJHAssocObj) wjh_associatedPointerWithKey:] and [NSObject(WJHAssocObj) wjh_associatedIntegerWithKey:] to fetch the associated values.

An association can be broken with WJHDisassociate or [NSObject(WJHAssocObj) wjh_disassociateKey:].

About

Provides support for associated objects using zeroing weak references

Resources

License

Stars

Watchers

Forks

Packages

No packages published