相关文章:
一提到给一个类添加点什么,我们有可能首先就想到类别
(Category)。那么我们就弄一下。
利用 Category 给现有的类添加属性
比如我们要给一个 NSArray 添加一个属性叫做NSString *name。
我们首先新建一个Objective-C文件。
File: Name
File Type:Category
Class:NSArray
然后我们在NSArray+Name.h
里面写
@interface NSArray (Name)
@property (nonatomic, copy) NSString *name;
@end
于是我们就给NSArray
这个类添加了一个NSString
类型的name
现在我们导入NSArray+Name.h
文件去实现一下代码验证一下
NSArray *array = [[NSArray alloc] init];
array.name = @"test";
NSLog(@"%@", array.name);
我们新建了一个NSArray
,并把@"test"
赋值给了array
的属性中。
然后输出看看这个属性是否成功赋值。
于是你很开心地按下了command+R,发现这家伙奔溃了,奔溃原因:
[__NSArray0 setName:]: unrecognized selector sent to instance 0x100102f80
NSArray
并没有这个setName:
这个方法,仔细一看 Xcode 还给我们两个警告。
于是我们进入NSArray+Name.m
文件写上 get 方法和 set 方法:
@implementation NSArray (Name)
- (void)setName:(NSString *)name {
_name = name;
}
- (NSString *)name {
return _name;
}
@end
很好,两个错误,因为并没有实例变量。或许你觉得可以添加一个扩展。于是你写了一个扩展并且给他添加了一个实例变量NSString *name
,然后这次连编译都不通过。
于是你哭了/(ㄒoㄒ)/~~
Category只能给已有的类添加方法,不能添加实例变量
那现在怎么办呢?难道我们之前的问题就解决不了了?
这个时候runtime的作用就体现出来了。之前我们说过,它可以动态的去修改我们创建的结构体(也就已经声明的类)。
利用 Runtime 和 Category 给现有的类添加属性
关联对象
关联对象是只将一个对象a利用一个key绑定一个对象b,之后a就可以利用这个key获取到这个对象b
同时,a可以二次绑定同一个key,并且会替换之前被绑定的对象。之后再通过key获取对象,就是一个新绑定的值了。
是不是感觉和普通的属性很像?可以赋值,可以取值,可以重复赋值然后覆盖。
的确,只是调用一个函数而已。
函数
Runtime 给了我们两个函数来实现关联对象,你只需要#import <objc/runtime.h>
就可以使用这两个函数了。
这两个函数分别是:
//set function
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
//get function
id objc_getAssociatedObject(id object, const void *key);
赋值函数
来看看 set 函数里的东西
object
要持有“别的对象”的对象,这里也就是指akey
关联关键字,是一个字符串常亮,是一个地址(这里注意,地址必须是不变的,地址不同但是内容相同的也不算同一个key)value
也就是值,你可以猜的出应该是值b了policy
这是一个枚举,你可以点进去看看这个枚举是什么:OBJC_ASSOCIATION_ASSIGN
OBJC_ASSOCIATION_RETAIN_NONATOMIC
OBJC_ASSOCIATION_COPY_NONATOMIC
OBJC_ASSOCIATION_RETAIN
OBJC_ASSOCIATION_COPY
如果你了解 Objective-C,那你一定知道上面这些枚举的作用了。
所以,我们就可以在前面的NSArray
的分类里这么写
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
取值函数
现在来看看 get 函数里的东西
- object 持有“别的对象”的对象,这里指a
- key 关联关键字
看完 set 函数之后,get 函数就显而易见了!这里不用多解释,立马就可以写代码
- (NSString *)name {
return objc_getAssociatedObject(self, "name");
}
验证结果
运行demo,成功输出如下内容:
2016-05-11 09:22:32.950 runtime+Category demo[923:36795] test
Program ended with exit code: 0
说明我们给 array 赋值的结果成功保留下来,下一次去取值可以成功取到上一次保存的值了。