美文网首页
极速理解runtime

极速理解runtime

作者: 进阶的蚊子 | 来源:发表于2017-08-30 14:28 被阅读11次

    一、关于runtime简介

    runtime  顾名思义,就是运行时的意思,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的。我们需要了解的是 Objective-C 是一门动态语言,它会将一些工作放在代码运行时才处理而并非编译时。

    OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。

    在C语言中,函数的调用在编译的时候会决定调用哪个函数。而对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。

    其实事实上在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错

    而在c语言中 ,在编译阶段,C语言调用未实现的函数就会报错.

    二、关于runtime作用

    由于运行时的应用比较广泛,我们暂时选择几种比较常见的容易理解的来介绍

    1.发送消息

      方法调用的本质,就是让对象发送消息。使用消息机制前提,必须导入#import<objc/message.h>

     消息机制原理:对象根据方法编号SEL去映射表查找对应的方法实现

    Student* stu=[[Student alloc]init];

    [stu study];

    // 本质:让对象发送消息

    objc_msgSend(stu, @selector(study));

    2.动态添加方法

    如果声明了某个方法 但是没有实现 ,编译成功,到那时运行会崩掉

    2017-08-30 12:01:00.453 runtimeTest[3228:71218] -[Student study]: unrecognized selector sent to instance 0x60800001ece0

    2017-08-30 12:01:00.460 runtimeTest[3228:71218] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Student study]: unrecognized selector sent to instance 0x60800001ece0'

    Student* stu=[[Student alloc]init];

    [stu study];

    //如果实现了study 打印如下:  2017-08-30 13:30:01.970 runtimeTest[4004:94732] 正在学习

    // 动态添加方法就不会报错  可以通过performSelector调用,但是会报错。

    [stu performSelector:@selector(study)];

    在student.m 中

    @implementation Student

    //-(void)study

    //{

    //    NSLog(@"正在学习");

    //}

    //动态添加

    void study(id self ,SEL sel){

    //打印出方法名

    NSLog(@"%@ %@",self,NSStringFromSelector(sel));

    }

    // 当一个对象调用未实现的方法,会调用这个方法处理,并且会把对应的方法列表传过来.

    // 刚好可以用来判断,未实现的方法是不是我们想要动态添加的方法

    + (BOOL)resolveInstanceMethod:(SEL)sel

    {

    if (sel == @selector(study)) {

    // 动态添加eat方法

    // 第一个参数:给哪个类添加方法

    // 第二个参数:添加方法的方法编号

    // 第三个参数:添加方法的函数实现(函数地址)

    // 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd

    class_addMethod(self, @selector(study), study, "v@:");

    }

    return [super resolveInstanceMethod:sel];

    }

    @end

    再次运行打印结果如下:

    2017-08-30 13:33:38.066 runtimeTest[4093:96918]study

    所谓动态添加就是 + (BOOL)resolveInstanceMethod:(SEL)sel 方法中判断方法是不是我们需要的,如果是就class_addMethod

    3  给分类添加属性

    也就是给一个类声明属性,其实本质就是给这个类添加关联

    我创建了一个User 类 ,什么都没添加,并且给创建了一个分类User (Name)

    #import "User.h"

    @interface User (Name)

    @property(nonatomic,strong)NSString* name;

    @end

    一开始并不实现属性的方法直接调用

    结果如下:

    2017-08-30 13:45:42.225 runtimeTest[4267:102049] -[User setName:]: unrecognized selector sent to instance 0x608000007f30

    2017-08-30 13:45:42.229 runtimeTest[4267:102049] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[User setName:]: unrecognized selector sent to instance 0x608000007f30'

    崩溃是在意料之中的

    我们再在.m文件做如下处理

    #import "User+Name.h"

    // 定义关联的key

    static  char *keyName = "name";

    @implementation User (Name)

    -(NSString*)name

    {

    // return objc_getAssociatedObject(<#id object#>, <#const void *key#>)

    //第一个参数 关联的object

    //第二个参数 关联的key

    return objc_getAssociatedObject(self, keyName);

    }

    -(void)setName:(NSString *)name

    {

    //objc_setAssociatedObject(<#id object#>, <#const void *key#>, <#id value#>, <#objc_AssociationPolicy policy#>)

    // 第一个参数:给哪个对象添加关联

    // 第二个参数:关联的key,通过这个key获取

    // 第三个参数:关联的value

    // 第四个参数:关联的策略

    objc_setAssociatedObject(self, keyName, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    }

    @end

    然后新运行

    2017-08-30 13:56:27.299 runtimeTest[4477:107135] ---蚊子---蚊子不吸血

      4   交换方法

    声明一个分类 NSString+More

    #import "NSString+More.h"

    #import <objc/runtime.h>

    @implementation NSString (More)

    //重新添加的一个方法用于交换

    + (void)makestringWithString:(NSString *)string

    {

    NSLog(@"新方法----%@",string);

    NSLog(@"新方法----%@",self);

    }

    //重写load方法

    + (void)load

    {

    //获取原来containsString的地址

    Method containsString=class_getClassMethod(self, @selector(stringWithString:));

    //获取原来addcontainsString的地址

    Method addcontainsString=class_getClassMethod(self, @selector(makestringWithString:));

    // 交换方法地址,相当于交换实现方式

    method_exchangeImplementations(containsString, addcontainsString);

    }

    @end

    调用方法

    NSString* str1=@"23333";

    [NSString stringWithString:str1];

    结果如下  可以看到执行了我们在.m 中实现的方法

    2017-08-30 14:23:07.596 runtimeTest[4929:120296] 新方法----23333

    2017-08-30 14:23:07.597 runtimeTest[4929:120296] 新方法----NSString

    这些基本上足够浅浅 的入门了,暂时就先介绍到这里 ,蚊子君以后空闲有了新的理解会持续更新

    相关文章

      网友评论

          本文标题:极速理解runtime

          本文链接:https://www.haomeiwen.com/subject/hpgzdxtx.html