iOS runtime从菜鸟到应用(小白理论篇)
前言唠唠嗑
前一段时间和大神们聊天,都在谈论runtime,然后我就一脸蒙逼了,只能不好意思的捂着眼睛听他们在侃。so,还是决定不能太丢人哈,这种装逼神级咱们也要掌握一下。一直有听到runtime这个词,总感觉高高在上,其实静下心来,也是挺好理解的。然后我就分享一下我的学习心得,供大家从0到1的掌握这门技巧。
一、什么是runtime?
不用什么大理论解释了,纯脑动讲解。RunTime简称运行时,这时候有心的同学就会说了,OC就是运行时机制,答对!其实runtime也就是在运行时候的一些机制,我们用到最多的就是消息机制。 runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。 在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者。
举例说明一下
OC : [[MJPerson alloc] init] runtime : objc_msgSend(objc_msgSend("MJPerson" , "alloc"), "init")
二:runtime可以干什么?
- 在程序运行过程中,动态创建一个类。(例如KVO的底层)
- 在程序运行过程中, 动态地为某个类添加属性\方法, 修改属性值\方法
- 遍历一个类的所有成员变量(属性)\所有方法
三:怎么和runtime交互?
OC中有三种与runtime交互的级别,分别是:
- 通过 Objective-C 源代码
- 通过 Foundation 库中定义的 NSObject 提供的方法
- 通过直接调用 runtime 方法
四:简单使用准备
1.通过OC源代码
在大多数的部分,运行时系统会自动运行并在后台运行。我们使用它只是写源代码并编译源代码。当编译包含 Objective-C 类和方法的代码时,编译器会创建实现了语言动态特性的数据结构和函数调用。该数据结构捕获在类、扩展和协议中所定义的信息。
最重要的 runtime 函数是发消息函数,在编译时,编译器会转换成类似 objc_msgSend 这样的发送消息的函数。因此,我们通过写好源代码,编译器会自动帮助我们编译成 runtime 代码。
(有些人可能说,我这说了段废话。不过,非也,知其然要知其所以然,本文就是介绍理论滴。。)
2.通过NSObject提供的方法
在 Cocoa 编程中,大部分的类都继承于 NSObject ,有些 NSObject 提供的方法仅仅是为了查询运动时系统的相关信息,这此方法都可以反查自己。比如 -isKindOfClass: 和 -isMemberOfClass: 都是用于查询在继承体系中的位置。 -respondsToSelector: 指明是否接受特定的消息。 +conformsToProtocol: 指明是否要求实现在指定的协议中声明的方法。 -methodForSelector: 提供方法实现的地址。
3.通过直接调用runtime函数
我们需要用到这两个头文件:
#import <objc/runtime.h>
#import <objc/objc.h>
举例子简单说明
发送消息
方法调用的本质,就是让对象发送消息。objc_msgSend,只有对象才能发送消息,因此以objc开头。
// 创建person对象
Person *p = [[Person alloc] init];
// 调用对象方法
[p eat]
// 本质:让对象发送消息
objc_msgSend(p, @selector(eat));
// 调用类方法的方式:两种
// 第一种通过类名调用
[Person eat];
// 第二种通过类对象调用
[[Person class] eat];
// 用类名调用类方法,底层会自动把类名转换成类对象调用
// 本质:让类对象发送消息
objc_msgSend([Person class], @selector(eat));
结语
理论知识难免枯燥乏味,但是只要掌握这门技术就一定要知其所以然,才能有长远的发展。今天先介绍下理论,很快将会发进阶篇,说说具体怎么应用。希望我的小小文字可以帮助你进步一点,谢谢支持。