I have a situation where it seems like I need to add instance variables to a category, but I know from Apple\'s docs that I can\'t do that. So I\'m wondering what the best a
Recently, I needed to do this (add state to a Category). @Dave DeLong has the correct perspective on this. In researching the best approach, I found a great blog post by Tom Harrington. I like @JeremyP's idea of using @property declarations on the Category, but not his particular implementation (not a fan of the global singleton or holding global references). Associative References are the way to go.
Here's code to add (what appear to be) ivars to your Category. I've blogged about this in detail here.
In File.h, the caller only sees the clean, high-level abstraction:
@interface UIViewController (MyCategory)
@property (retain,nonatomic) NSUInteger someObject;
@end
In File.m, we can implement the @property (NOTE: These cannot be @synthesize'd):
@implementation UIViewController (MyCategory)
- (NSUInteger)someObject
{
return [MyCategoryIVars fetch:self].someObject;
}
- (void)setSomeObject:(NSUInteger)obj
{
[MyCategoryIVars fetch:self].someObject = obj;
}
We also need to declare and define the class MyCategoryIVars. For ease of understanding, I've explained this out of proper compilation order. The @interface needs to be placed before the Category @implementation.
@interface MyCategoryIVars : NSObject
@property (retain,nonatomic) NSUInteger someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance;
@end
@implementation MyCategoryIVars
@synthesize someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance
{
static void *compactFetchIVarKey = &compactFetchIVarKey;
MyCategoryIVars *ivars = objc_getAssociatedObject(targetInstance, &compactFetchIVarKey);
if (ivars == nil) {
ivars = [[MyCategoryIVars alloc] init];
objc_setAssociatedObject(targetInstance, &compactFetchIVarKey, ivars, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[ivars release];
}
return ivars;
}
- (id)init
{
self = [super init];
return self;
}
- (void)dealloc
{
self.someObject = nil;
[super dealloc];
}
@end
The above code declares and implements the class which holds our ivars (someObject). As we cannot really extend UIViewController, this will have to do.