你的位置:首页 > 操作系统

[操作系统]iOS开发中runtime介绍


一.runtime简介

  • RunTime简称运行时。OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
  • 对于C语言,函数的调用在编译的时候会决定调用哪个函数
  • 对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
  • 事实证明:
    • 在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错。
    • 在编译阶段,C语言调用未实现的函数就会报错。
  • 使用runtime之前需要对环境进行如下配置:Enable Strict 选择No。

二.runtime的作用

1.发送消息
    •    方法调用的本质,就是让对象发送消息。
    •    objc_msgSend,只有对象才能发送消息,因此以objc开头.
    •    使用消息机制前提,必须导入#import <objc/message.h>
    •    进入文件所在路径,在终端使用clang -rewrite-objc main.m 指令可查看最终生成代码。

1   // NSObject *objc = [NSObject alloc];2   NSObject *objc = objc_msgSend([NSObject class], @selector(alloc));3 4   // objc = [objc init];5   objc = objc_msgSend(objc, @selector(init));6   7   NSLog(@"%@",objc);

消息机制作用:【调用已知的私有方法】

例:Person类中有两个私有方法。

 1 #import <Foundation/Foundation.h> 2  3 @interface Person : NSObject 4  5 @end 6  7 @implementation Person 8  9 - (void)run:(NSInteger)meter10 {11   NSLog(@"跑了%ld米",meter);12 }13 14 - (void)eat15 {16   NSLog(@"吃东西");17 }18 19 @end

 1 #import <objc/message.h> 2 #import "Person.h" 3  4 @interface ViewController () 5  6 @end 7  8 @implementation ViewController 9 10 - (void)viewDidLoad {11   [super viewDidLoad];12   13   //Person *p = [Person alloc];14   Person *p = objc_msgSend([Person class], @selector(alloc));15   16   //p = [p init];17   p = objc_msgSend(p, @selector(init));18   19   // 调用eat20   //[p eat];21   objc_msgSend(p, @selector(eat));22   23   // runtime24   // 方法编号后面开始,依次就是方法参数排序25   // objc_msgSend(id self, SEL op, ...)26   objc_msgSend(p, @selector(run:),20);27 }

    // 调用【类方法】的方式有两种
    // 第一种通过类名调用
    [Person eat];
    // 第二种通过类对象调用
    [[Person class] eat];
    
    // 用类名调用类方法,底层会【自动把类名转换成类对象调用】
    // 本质:让【类对象发送消息】
    objc_msgSend([Person class], @selector(eat));

说到这里,不得不问:对象如何找到对应的方法去调用?

回答这个问题,首先要清楚:方法保存到什么地方?--->对象方法保存到类中,类方法保存到元类(meta class)中。每一个类都有方法列表methodList。
    1.根据对象的isa指针去对应的类中查找方法。isa:判断去哪个类查找对应的方法 指向方法调用的类。
    2.根据传入的方法编号(SEL),才能在方法列表中找到对应方法Method(方法名)。
    3.根据方法名(函数入口)找到函数实现。

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


外界使用:无需导入分类头文件,直接使用imageNamed:方法即可实现判断图片是否加载成功。

 1 #import "ViewController.h" 2  3 @interface ViewController () 4  5 @end 6  7 @implementation ViewController 8  9 - (void)viewDidLoad {10   [super viewDidLoad];11 12   [UIImage imageNamed:@"123"];13 }