利用类别(Category)为对象添加“实例变量”

Add a instance variable to object with category

类别(Category)是Objective-C比较常用的一个特性。常常用来扩展一功能类、将不同的功能分属不同的文件、以及为现场的类添加新的方法和功能,甚至有的时候我们也会用以重装某些方法来实现多态或满足其他需求(不提倡,原因暂不予讨论)。但是,我们只能添加方法,却不能通过类别给已经存在的类添加新的成员变量。因此,每有变量增需,一般都是采用继承。
但是如果确有添加有限个成员变量却不想再产生一个子类,通过类别倒是也能实现,这需要利用ObjectiveC的C API中函数:

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
id objc_getAssociatedObject(id object, const void *key)

详细参见官方的 ObjectiveC Runtime Reference
废话到此结束,现在写怎么做(以给UIView添加一个string成员作为名字为例):

i. 在定义类别之前, 首先引入<objc/runtime.h>.

#import <objc/runtime.h>

ii. 定义&实现类别(以UIView为例)

定义:

@interface UIView(AddVariables)
@property (nonatomic, retain) NSString *viewName;
@end

实现:

// 定义存取的Key
static const char *viewNameKey = "viewNameKey";

@implementation UIView(AddVariables)
// get方法
- (NSString *)viewName {
    return (NSString *)objc_getAssociatedObject(self, viewNameKey);
}
// set方法
- (void)setViewName:(NSString *)newViewNameKey {
    objc_setAssociatedObject(self, viewNameKey, newViewNameKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

iii. 调用测试:

- (void)viewDidLoad {

    UIView *testView = [[UIView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:testView];
    [testView release];

    [testView setViewName:@"Nori's View"];
    NSLog(@"[testView's newPropery]:%@", testView.viewName);

    [super viewDidLoad];
}

输出结果如下:

testView's newPropery:Nori's View

附件1