iOS-了解Runtime

一.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 是运行时】什么情况下用runtime?大部分人能...
    梦夜繁星阅读 3,732评论 7 64
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,758评论 0 9
  • 本文分为4个部分 1.介绍OC和C语言之间的转换 2.介绍运行时和相关术语 3.介绍消息发送机制已及怎样找到函数实...
    一片枫叶随风舞阅读 316评论 0 1
  • 幸福莲发起共享美容财富新思维 大众创新、万众创业 新时代的列车缔造新的财富中心 您选择就是顺势而为,站在风口上前行...
    李紫誠阅读 428评论 0 0
  • 这个月以来,最不想过的,是星期二。老师的测验我已经两次都没过了。我不明白,一个大学老师为何如此苛刻,我因为一个符号...
    谦哥xxx阅读 269评论 0 1