在介绍protocol的时候我们知道Category实际上就是非正式协议。文中我也提到了一个问题:Category是不能够添加变量,当添加变量成员变量时Xcode会主动报错Expected identifier or '{',但是却能够添加属性。
系统的定义的类基本上都会有Category,例如UIView中的UIView(UIViewGeometry)、UIView(UIViewHierarchy)、UIView(UIViewRendering)等等,每部分实现一个功能。
那为什么能够在Category中添加属性?
首先“属性=成员变量+setting方法+getting方法”,这是解释的关键,但是添加属性还是要添加方法,那不是自相矛盾了吗?其实并不然,是否记得Runtime的作用中有一个动态添加成员变量和方法,这就是问题的答案。在定义属性的setting方法时可以动态添加成员变量。
示例:
分类.h
#import "Programmer.h"
@interface Programmer (Category)
@property(nonatomic,copy) NSString *nameWithSetterGetter; //设置setter/getter方法的属性
- (void) programCategoryMethod; //分类方法
@end
分类.m
#import "Programmer+Category.h"
#import <objc/runtime.h>
static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey";
@implementation Programmer (Category)
- (void)setNameWithSetterGetter:(NSString *)nameWithSetterGetter {
objc_setAssociatedObject(self, &nameWithSetterGetterKey, nameWithSetterGetter, OBJC_ASSOCIATION_COPY);
}
- (NSString *)nameWithSetterGetter {
return objc_getAssociatedObject(self, &nameWithSetterGetterKey);
}
- (void)programCategoryMethod {
NSLog(@"实现分类方法");
}
@end
原因已经解释清楚,在此延伸下示例中的Runtime关键函数。
objc_setAssociatedObject
objc_setAssociatedObject来把一个对象与另外一个对象进行关联。该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略。
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
- 关键字是一个void类型的指针。每一个关联的关键字必须是唯一的。通常都是会采用静态变量来作为关键字。
- 关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。这种关联策略是通过使用预先定义好的常量来表示的。
对应的断开关联有objc_removeAssociatedObjects方法;取关联有objc_getAssociatedObject方法。