无论谁在设计一个类的时候多么nice,但是在以后的更新迭代中,都会感觉以前的类行为还是有点欠缺。那怎么办Objective-C 2.0 中提供了一个新的特性,就是可以动态的给一个类添加新的行为,这感觉这就是神一样的队友啊,虽然其他的语言也有这个特性。
category的作用
a)可以给一个类动态的添加新的行为。
b)可以将一个大的文件,分解为多个category文件,可以多个人共同开发同一个类。
Category和Extension的区别
一个和匿名的category相似的东西那就是Extension,但是她们的使用上有很大的区别
a)Extension 是在编译期决定的,在编译期间将和interface 、implement一起形成一个完整的类。
一个有源码的类可以添加Extension,所以无法给系统的类添加Extension。
b) Extension 可以添加实例变量。
c)Category 是在运行期决定的,不可以添加实例变量。
Category 内在有没有货
OC类和对象,在runtime层都是用struct表示的,category也逃脱不了
在runtime.h 中可以看到下面信息
typedef struct objc_category *Category;
struct objc_category {
char *category_name OBJC2_UNAVAILABLE;
char *class_name OBJC2_UNAVAILABLE;
struct objc_method_list *instance_methods OBJC2_UNAVAILABLE;
struct objc_method_list *class_methods OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
}
包含了
1)、类的名字(name)
3)、category中所有给类添加的实例方法的列表(instanceMethods)
4)、category中所有添加的类方法的列表(classMethods)
5)、category实现的所有协议的列表(protocols)
6)、category中添加的所有属性(instanceProperties)
从category的定义也可以看出category的可为(可以添加实例方法,类方法,甚至可以实现协议,添加属性)
不可以添加实例变量
下面可以写一个类添加两个category
然后调用下面这个方法即可将类中所有的方法,都可以列出来,可以验证Category中方法重写的问题。只是检测方法是顺序检测的,不知道后面还有一个同名的方法。
也可以在资源加载的时候将category的顺序换一下,即可得到不同的结果
- (void)testCategoryOverridSystemMethod
{
typedef void (*functionn) (id, SEL);
Class currentClass = [FirstObject class];
FirstObject * myButton = [FirstObject new];
if (currentClass) {
unsigned int methodCount;
//通过类名得到方法列表
Method * methodList = class_copyMethodList(currentClass, &methodCount);
//NSLog(@"method list :%@",methodList);
IMP lastImp = NULL;
SEL lastSel = NULL;
for (NSInteger i = 0 ; i < methodCount; i ++) {
Method method = methodList[i];
//得到方法名并转为NSString
NSString * methodName = [NSString stringWithCString:sel_getName(method_getName(method)) encoding:NSUTF8StringEncoding];
NSLog(@"method Name :%@",methodName);
if ([@"printName" isEqualToString:methodName]) {
NSLog(@"into here test Category .... ");
//得到方法对应的函数的指针
lastImp = method_getImplementation(method);
//得到方法的名字 SEL类型
lastSel = method_getName(method);
if (lastImp!= NULL) {
functionn f = (functionn)lastImp;
//传入类名/实例名 、方法的SEL、对应参数 开始调用方法
f(myButton,lastSel);
}
}
}
NSLog(@"out of for ....");
if (lastImp!= NULL) {
functionn f = (functionn)lastImp;
//传入类名/实例名 、方法的SEL、对应参数 开始调用方法
f(myButton,lastSel);
}
//释放方法列表
free(methodList);
}
}
现在基本可以知道为什么category中的方法的调用和构成了。
如果还想知道category中的方法是如何添加到类中可以使用命令
clang -rewrite-objc main.m
然后会编译出一个代码特别多的.cpp文件
可以自行阅读,这就不贴了,实在是太多了。