美文网首页
iOS-了解Runtime

iOS-了解Runtime

作者: a浮生若梦a | 来源:发表于2017-09-08 15:03 被阅读0次

    一.Runtime是什么?

    Runtime也叫运行时态,是iOS底层用C语言函数和汇编语言封装的一套API,我们的程序在运行过程中,都是基于Runtime实现的。

    二.Runtime的消息机制

    //例如我们创建一个People类
    People * pe = [[People alloc] init];
    
    //通过objc_msgSend函数来发送消息,转换为:
    id pe = objc_msgSend(objc_msgSend([Person class], @selector(alloc)), @selector(init));
    
    //再通过objc_getClass和sel_registerName函数往下转换为:
    id pe = objc_msgSend(objc_msgSend(objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
    
    • 这就是消息发送机制。
    • 苹果封装了消息机制,一般不建议大家使用底层的消息机制。

    这是下面讲的Demo下载地址

    二.Runtime演示一

    • 这里用OC的归档和解档来当例子,不知道可以查看前面我写的 iOS归档和解档

    • 我们知道OC的序列化是把model转化为二进制存储,使用也很方便,但是如果一个model的属性很多的话,在写归档或者解档的时候 对我们来说就成了一种负担,这里就用到Runtime来解决。
    • 下面进入主题

      • 导入头文件(Runtime系统是具有公共接口的动态共享库。头文件存放于/usr/include/objc目录下,这意味着我们使用时只需要引入objc/Runtime.h头文件即可。)
      1.导入头文件 #import <objc/runtime.h>
      2.获取类成员变量列表,返回类的所有属性和变量
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList([UIButton class], &count);
        //第一个参数填写类(这里写button),第二个参数count为类成员的数量
      3.通过指针取出button数据
        Ivar ivar = ivars[0]; (默认第一个可以通过循环获取每个数据)
      4.获取数据name,返回C的字符串
        const char *name = ivar_getName(ivar);
        //转换成OC字符串(这里获取到成员变量的name)
        NSString *nameStr = [NSString stringWithUTF8String:name];
      5.nameStr就是获取到button的一些私有变量
      
      • 解档和归档用runtime来获取成员变量修改成如图所示(图中注释的三行为之前的原代码) 归档 解档
    • 下面我删除app重新运行一下,ViewController里面写两个button,和两个对应的点击方法(归档方法和解档方法) 运行之后先点击一下解档按钮 此时控制台输出(解档方法里面有个输出) 发现输出数据都是null,Don't worry😺,这是因为还有没归档,所以解档是没有数据的。 接下来我点击一下归档,然后我再点击一下解档,这个时候就可以看到有输出信息了,说明用runtime改写成功。(是不是很简单呢😊)
    • 小结:通过runtime可以获取到类的一些私有变量和私有方法。

    二.Runtime演示二

    • 首先我们都知道NSURL * url = [NSURL URLWithString:@"这里填写请求的URL字符串"];里面填写请求URL字符串,如果拼出来的字符串 http://baidu.com?p1=%+&sd f&p2=这里有汉字中有汉字、特殊符号&%和空格等,必须进行转译才能正确访问,这个时候就需要对 URL 进行 Encode。如果填写的URL里面有中文的话,返回的URL对象为nil(这里只举例包含汉字的URL访问)


      那么我能不能封装一下,在调用方法内部的时候如果请求的URL包含文字就调用自己写的方法实现,如果不包含文字就调用系统原来的方法实现,我能不能截取到这个方法改成我自己的方法呢?这里我们就可以用Runtime来解决。
      • 首先创建一个URL的类别,CNSURL
      • 在NSURL+CNSURL.m里面,重写一个CHURLWithString方法(isContainChinese方法用来判断是否包含中文)如图所示 上图中要注意方法里面调用本方法其实是调用NSURLWithString的方法实现,这一点一定要搞清楚。
      • 通过进行方法交换来实现:

      1.导入头文件 #import <objc/runtime.h>
      2.写load方法,因为load方法在程序一进来的时候就开始执行,比main函数都早。
      3.在load方法里 class_getClassMethod(类, 方法名) 用来获取类方法。
        class_getInstanceMethod(类, 方法名) 用来获取实例方法。
        method_exchangeImplementations(方法一, 方法二) 用来交换两个方法的实现。
      
      • 在ViewController中实现两个按钮一个有文字URL,一个没有文字URL
      • 点击第一个没有文字的URL,控制台输出
      • 点击第二个有文字的URL,控制台输出
      • 说明点击按钮的时候调用URLWithString方法(第一个输出打印的是判断文字的输出,然后打印出编码处理的输出,最后打印出上图中的一行输出) 其实是调用了NSURL+CNSURL里面的CHURLWithString方法。
    • 小结:在OC的Runtime中任何方法的调用其内部都是发送消息,上面是通过发送消息来找到方法编号(SEL),通过方法编号来找到方法实现(IMP),这里把方法实现改成CHURLWithString这个的方法实现,这叫方法欺骗。

    相关文章

      网友评论

          本文标题:iOS-了解Runtime

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