如果我们想重写一个类的方法的时候,我们会考虑到用哪些方法呢?
1.用分类:用分类主要的缺点是,分类是没有父类的,不能调用父类的方法。而且需要引入头文件,容易被人发现
2.用继承: 继承虽然能实现重写父类的方法,但是动作太大,容易被人发现
3.runtime: 方法交换,虽然用到了分类,但是不需要引入头文件
基本概念:
RunTime简称运行时,就是系统在运行的时候的一些机制,其中最主要的是消息机制。
对于C语言,函数的调用在编译的时候会决定调用哪个函数,编译完成之后直接顺序执行,无任何二义性。
OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。
只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。
每一个oc的方法,底层必然有一个与之对应的runtime方法。
1.发送消息
objc_msgSend:使用消息机制前提,必须导入#import<objc/message>
例如:objc_msgSend([Person class], @selector(eat));
2..交换方法
开发使用场景:系统自带的方法功能不够,给系统自带的方法扩展一些功能,并且保持原有的功能
// 获取imageWithName方法地址
Method imageWithName = class_getClassMethod(self, @selector(imageWithName:));
//获取imageWithName方法地址
Method imageName = class_getClassMethod(self,@selecotr(imageNamed:));
//交换方法地址,相当于交换实现方法
method_exchangeImplementations(imageWithName, imageName);
不能在分类中重写系统方法imageNamed,因为会把系统的功能给覆盖掉,而且分类中不能调用super
3.动态添加方法
开发使用场景:如果一个类方法非常多,加载类到内存的时候也比较耗费资源,需要给每个方法生成映射表,可以使用动态给某个类,添加方法解决。
经典面试题:有没有使用performSelector,其实主要想问你有没有动态添加过方法。
// 默认person的实例,没有实现eat方法,可以通过performSelector调用,但是会报错。
// 动态添加方法就不会报错
1.动态给person类中添加eat方法
class_addMethod([person class], @selector(eat), (IMP)eatFood, "v@:");
参数说明: (IMP)eatFood 意思是eatFood的地址指针;
"v@:" 意思是,v代表无返回值void,如果是i则代表int;@代表 id sel; : 代表 SEL _cmd;
“v@:@@” 意思是,两个参数的没有返回值。
2. 调用eat方法响应事件:[p performSelector:@selector(eat)];
3.编写eatFood的实现
void eatFood(id self, SEL _cmd){ NSLog(@" eatFood") } ;
注意:
void的前面没有+、-号,因为只是C的代码。
必须有两个指定参数(id self,SEL _cmd)
4.给分类添加属性
原理:给一个类声明属性,其实本质就是给这个类添加关联,并不是直接把这个值的内存空间添加到类存空间。
// 根据关联的key,获取关联的值。
static const char *key = "name";
return objc_getAssociatedObject(self, key);
// 第一个参数:给哪个对象添加关联
// 第二个参数:关联的key,通过这个key获取
// 第三个参数:关联的value
// 第四个参数:关联的策略
objc_setAssociatedObject(self, key, name, dynamicStr,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
5.字典转模型
思路:利用运行时,遍历模型中所有属性,根据模型的属性名,去字典中查找key,取出对应的值,给模型的属性赋值。
步骤:提供一个NSObject分类,专门字典转模型,以后所有模型都可以通过这个分类转
6、获得一个类的所有成员变量
需要用到的方法<objc/runtime.h>
获得某个类的所有成员变量,包括{}里面的成员变量(outCount 会返回成员变量的总数)
Ivar *class_copyIvarList(Class cls , unsigned int *outCount)
for (unsigned int i; i<count;i++{
Ivar myIvar = ivarList[i];
const char *ivarName = ivar_getName(myIvar);
NSLog(@"Ivar---->%@", [NSString stringWithUTF8String:ivarName]);
}
获取属性列表 不包括{}里面的成员变量
objc_property_t *propertyList = class_copyPropertyList([self class], &count);
const char *propertyNmae = property_getName(propertyList[i]);
NSLog(@"property --->%@",[NSString stringWithUTF8String:propertyName]);}
获取方法列表
Method *methodList = class_copyMethodList([self class], &count);
Method method = methodList[i];
NSLog(@"method---->%@", NSStringFromSelector(method_getName(method)));
获得成员变量的名字 const char *ivar_getName(Ivar v)
获得成员变量的类型 const char *ivar_getTypeEndcoding(Ivar v)
获取协议列表
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count);
Protocol *myProtocal = protocolList[i];
const char *protocolName = protocol_getName(myProtocal);
NSLog(@"protocol---->%@", [NSString stringWithUTF8String:protocolName]);
相关链接:http://ios.jobbole.com/87415/