runtime知识整理

如果我们想重写一个类的方法的时候,我们会考虑到用哪些方法呢?

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/



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容