前言
在iOS开发中,category
作用十分巨大,在实际项目中,我们可以通过添加一个类的category
来实现任意地方调用我们已经准备好的方法,或者是对现有的一些类进行扩展。
最常见的应用莫过于为ViewController
添加分类,在分类中准备好方法,这样一来我们可以在任意控制器去调用我们准备好的方法。
由于catagory
的特性,使得我们在其中只能添加方法并不能添加属性,这大大限制了我们的使用。
好在Objective-C的动态特性为我们带来了希望。
本文通过利用Objective-C的动态特性,在运行时动态添加属性,动态绑定,达到category
中添加属性的目的。
分析
首先,我们先看一下property
的构成
@property的本质其实是 ivar(实例变量)+getter+setter
也就是说,为category添加属性的方法,其本质上是我们人为创造一个property
,通过准备实例变量,自行实现setter
方法和getter
方法,来达到目的。
接下来我们看看需要用到的runtime部分。
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
objc_getAssociatedObject
这个方法中需要用到两个参数,object
和key
由于当前方法在分类中,并且我们获取的属性也是当前类下的属性,object
这边指的是self
。
而这里的key
代表的是属性的标记,通过这个key
来查找对应的属性。
//key的写法
1、static void *key = &key;
2、static NSString *const key = @"key";
3、static char const * const key = "key";
objc_setAssociatedObject
这个方法中前两个参数同上,后两个参数分别代表关联的属性,和关联策略。
关联属性策略如下,根据实际使用选择关联策略。
enum {
OBJC_ASSOCIATION_ASSIGN = 0, //关联对象的属性是弱引用
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, //关联对象的属性是强引用并且关联对象不使用原子性
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, //关联对象的属性是copy并且关联对象不使用原子性
OBJC_ASSOCIATION_RETAIN = 01401, //关联对象的属性是copy并且关联对象使用原子性
OBJC_ASSOCIATION_COPY = 01403 //关联对象的属性是copy并且关联对象使用原子性
};
实例
在头文件.h中添加一个property
,如:
@property (nonatomic,assign) BOOL animateInvalid;
.m实现:
static char const * const kanimateInvalid = "kanimateInvalid";
#import <objc/runtime.h>
@implementation UIViewController (Associate)
@dynamic animateInvalid;//手动实现getter和setter
- (BOOL)animateInvalid{
return [objc_getAssociatedObject(self, kanimateInvalid) boolValue];
}
- (void)setAnimateInvalid:(BOOL)animateInvalid{
objc_setAssociatedObject(self, kanimateInvalid, @(animateInvalid), OBJC_ASSOCIATION_ASSIGN);
}
至此在category中添加属性已经完成。掌握方法在实际项目中能够发挥十分大的作用,大大提高我们编程的效率。