iOS面试-Runtime简介

本文主要介绍runtime的五点

  • Runtime简介
  • Runtime(消息机制)
  • Runtime方法调用流程
  • Runtime(交换方法&自定义UIImage)
  • Runtime(动态添加方法)
  • Runtime(动态添加属性)
一.runtime简介
  • runtime简称运行时,OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
  • 对于C语言,函数的调用在编译时会决定调用哪个函数
  • 对于OC的函数,属于动态调用过程,在编译的时候不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
  • 事实证明:
    ① 在编译阶段:OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错。
    ② 在编译阶段:C语言调用未实现的函数就会报错。

runtime的五个功能

1.发送消息
2.交换方法
3.动态添加方法
4.给分类添加属性
5.字典转模型

  • 方法调用的本质,就是让对象发送消息。
  • objc_msgSend,只有对象才能发送消息,因此以objc开头。
  • 使用消息机制前提,必须导入#import <objc/runtime.h>
  • 消息机制简单使用。
  • clang-rewrite-objc main.m查看最终生成代码。
二.Runtime(消息机制)

消息机制是OC中是最主要的机制,任何方法的调用本质都是发送消息,用runtime发送消息,OC底层通过runtime来实现。
验证:
是否真的是转换为消息机制
第一步:cd进入到该文件夹
第二步:在终端执行clang -rewrite-objc 文件名 命令
第三步:该命令成功后就会生成一个.cpp的文件。

allisondeMacBook-Pro:123 allison$ clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk ViewController.m
clang: warning: using sysroot for 'iPhoneSimulator' but targeting 'MacOSX' [-Wincompatible-sysroot]
/var/folders/nm/4974_cj15s5gyjfg8wj077qm0000gn/T/ViewController-78b550.mi:12798:188: warning: 
      'kCFCalendarUnitWeek' is deprecated: first deprecated in macOS 10.10 - Use
      kCFCalendarUnitWeekOfYear or kCFCalendarUnitWeekOfMonth instead
      [-Wdeprecated-declarations]
  ...or NSCalendarUnitWeekOfYear, depending on which you mean"))) = kCFCalend...
                                                                    ^
/var/folders/nm/4974_cj15s5gyjfg8wj077qm0000gn/T/ViewController-78b550.mi:5147:2: note: 
      'kCFCalendarUnitWeek' has been explicitly marked deprecated here
 kCFCalendarUnitWeek __attribute__((availability(macos,introduced=10.4,d...
 ^
1 warning generated.

查看ViewController.cpp文件,我们发现有64871行代码,查找viewDidLoad方法,我们看.cpp文件中viewDdiload方法中生成的代码:

// @implementation ViewController

static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));


    id objc = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc"));
    objc = ((id (*)(id, SEL))(void *)objc_msgSend)((id)objc, sel_registerName("init"));

}

我们ViewController.m写的代码

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    id objc = [NSObject alloc];
    objc = [objc init];
}

例子:运用运行时去创建一个NSObject对象。(我们可以参考ViewController.cpp类里面的viewDidLoad方法)

    id objc = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc"));
    objc = ((id (*)(id, SEL))(void *)objc_msgSend)((id)objc, sel_registerName("init"));

上面这个是最底层的,下面我们可以用苹果封装好的方法,效果是一样的:

    id objc = objc_msgSend([NSObject class], @selector(alloc));
    objc = objc_msgSend(objc, @selector(init));

这里,从控制台我们可以发现,我们已经分配内存,并且没有错误。


msg01.png

Tips1

本来想在main函数中试验,但是在main函数中的时候,使用 allison$ clang -rewrite-objc main.m命令的时候总是报如下错误,所以最后在ViewController中生成cpp文件成功。(暂不清楚原因,还请各位知道的留言指正)

allisondeMacBook-Pro:Clang allison$ clang -rewrite-objc main.m
main.m:9:9: fatal error: 'UIKit/UIKit.h' file not found
#import <UIKit/UIKit.h>
        ^~~~~~~~~~~~~~~
1 error generated.
allisondeMacBook-Pro:

Tips2

我们用objc_msgSend函数的时候,可能没有提示,这是因为在xcode6之后,苹果不推荐使用runtime,因为苹果不想让开发者了解底层的实现,只想让开发者直接使用API即可。但是这里,我们可以将严格检测消息机制这个选项关闭,使用objc_msgSend函数的时候便会提示了,设置如下图所示:

msg02.png
msg03.png
三. Runtime(消息机制调用多个参数)

开发中什么时候用runtime?

1.可以帮我们调用私有的方法。(例子:同事封装的一个比较好的类,该类中都是私有方法,我们想使用该方法,一般是不会直接修改.h文件,这个时候可以使用runtime来实现)。

2.苹果系统API中,如果发现某个私有的API比较好用,如果我们想使用,可以通过objc_msgSend来调用私有的api。

四.方法调用流程

调用set方法对象方法:类对象的方法列表;类方法:元类中方法列表。

  • 内存五大区:
  • 1.栈:不需要手动管理内存,自动管理
  • 2.堆:需要手动管理内存,手动释放
  • 3.静态区
  • 4.常量区
  • 5.方法区

方法调用流程:

方法调用流程.png

1.通过isa指针去对应的类中查找。
2.注册方法编号
3.根据方法编号去查找对应的方法。
4.找到只是最终函数实现地址,根据地址去方法区调用对应函数。

五.Runtime(交换方法&自定义UIImage)

开发中什么时候使用runtime(交换方法)?
需求1:每次UIImage加载图片,返回是否加载成功!

方法1.:自定义UIImage类。
弊端:①.每次使用都需要导入 ②.老项目/大项目大量使用UIImage,替换不易。
方法2: 给UIImage添加分类。
弊端:①.在分类中方最好不要重写系统方法,一旦重写,把系统方法实现就给覆盖了。②分类中不能调用super方法。
方法3:使用runtime(交换方法)来实现。

交换方法.png

(1)给系统的方法添加分类。
(2)自己实现一个带有扩展功能的方法,如:bdf_imageNamed
(3)交换imageNamedbdf_imageNamed方法。

主要代码:

    // 获取系统方法
    // Class  _Nullable __unsafe_unretained cls 获取那个类的方法
    // SEL  _Nonnull name:获取那个方法
    Method imageNameMethod = class_getClassMethod(self, @selector(selectedImage:));
    // 获取自定义方法
    Method bdf_imageNameMethod = class_getClassMethod(self, @selector(bdf_selectedImage:));
    // 交换方法
    method_exchangeImplementations(imageNameMethod, bdf_imageNameMethod);
六.Runtime(动态添加方法)

起源:面试题中,问有没有使用过performSelector?
self performSelector:<#(SEL)#>
答:动态添加方法的时候使用过!
这里请自行查阅runtime官方文档进行了解。目前没有get到Runtime动态添加方法方法的用处~ 😂

七.Runtime(动态添加属性)

开发中什么时候需要动态添加属性?
场景1:在分类中添加属性,通过objc_setAssociatedObject方法添加属性。
场景2:给系统的类添加属性的时候,可以使用runtime动态添加属性方法。
如:

- (void)setName:(NSString *)name {
    // id  _Nonnull object 给那个对象添加属性
    // const void * _Nonnull key 属性名称
    // id  _Nullable value 属性值
    // objc_AssociationPolicy policy 保存策略
    objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name {
    return objc_getAssociatedObject(self, @"name");
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容