runtime—新手必学
1.RunTime消息机制
1.消息机制是运行时里面最重要的机制,OC中任何方法的调用,本质都是发送消息。
MyClass *object = [[MyClass alloc] init]; 就会调这个实例化方法:[object showUserName];
•在编译阶段,[object showUserName] 会被编译器转化为: objc_msgSend(object, "showUserName"),相当于一种“发消息”的行为。
• 在运行阶段,执行到上述的objc_msgSend这个函数时,函数内部会到object对应的内存地址,寻找showUserName这个方法的地址并执行。如果找不到,就会抛一个“unknown selector sent to instance”的异常。
clang -rewrite-objc MyClass.m(把oc代码转写成
c/c++代码,我们常用它来窥探OC的底层实现),不一会在原来的同一目录下会多出一个 MyClass.cpp 文件
init 方法已经被编译器转化为下面这样:
objc_msgSend 函数被定义在 objc/message.h 目录下,其函数原型是:
OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ )
id 类型(消息接收对象),一个 SEL 类型(方法的selector)。
@selector (SEL):是一个SEL方法选择器。SEL其主要作用是快速的通过方法名字查找到对应方法的函数指针,然后调用其函数。SEL其本身是一个Int类型的地址,地址中存放着方法的名字。
SEL。所以一个类中不能存在2个名称相同的方法(有歧义。。。),即使参数类型不同,因为SEL是根据方法名字生成的,相同的方法名称只能对应一个SEL。
- (void)go {} + (void)go {} 这两个方法可以共存(我们知道,这两个方法的名字都是go)。
runtime都会根据方法名去这个对象所属的这个类的方法列表中查找方法,而方法列表的外层应该是一个字典,根据所传的接收消息对象不同,查找的方法列表也不同。
objc_msgSend([MyClass class], @selector(go));
objc_msgSend([[MyClass alloc] init], @selector(go));
Id :是一个结构体指针类型,它可以指向 Objective-C 中的任何对象。
Class vclass = NSClassFromString(@"ViewController");
id vc = [[vclass alloc] init];
objc_object 结构体定义如下:
struct objc_object { Class isa OBJC_ISA_AVAILABILITY;};
isa,对象可以通过 isa 指针找到其所属的类。isa 是一个 Class 类型的成员变量,那么 Class 又是什么呢?如下:
•·Class 也有一个 isa 指针,指向其所属的元类(meta)。
•·super_class:指向其超类。
•·name:是类名。
•·version:是类的版本信息。
•·info:是类的详情。
•·instance_size:是该类的实例对象的大小。
•·ivars:指向该类的成员变量列表。
•·methodLists:指向该类的实例方法列表,它将方法选择器和方法实现地址联系起来。methodLists 是指向 ·objc_method_list 指针的指针,也就是说可以动态修改 *methodLists 的值来添加成员方法,这也是 Category 实现的原理,同样解释了 Category 不能添加属性的原因。
•·cache:Runtime 系统会把被调用的方法存到 cache 中(理论上讲一个方法如果被调用,那么它有可能今后还会被调用),下次查找的时候效率更高。
•·protocols:指向该类的协议列表。
•底层调用 [p performSelector:@selector(eat)] 方法,编译器在将代码转化为 objc_msgSend(p, @selector(eat))把方法的调用者和方法选择器当做参数传递过去。
•首先,检测这个 selector 的 target 是不是 nil,Objc 允许我们对一个 nil 对象执行任何方法不会 Crash,因为运行时会被忽略掉。
•如果target != nil,方法的调用者会通过 isa 指针来找到其所属的类,然后在 cache 中查找该方法,找得到就跳到对应的方法去执行。
•若 cache 中未找到,再去 methodList 中查找。若能找到,则将 method 加入到 cache 中,以方便下次查找,并通过 method 中的函数指针跳转到对应的函数中去执行。
•若 methodlist 中未找到,则去 superClass 中查找,一直找到 NSObject 类为止。若能找到,则将 method 加入到 cache 中。
•如果还是查不到,则会执行消息转发,抛出异常。
2.RunTime交换方法
eg:实现image添加图片的时候,自动判断image是否为空,如果为空则提醒图片不存在。
:
1.自定义类, 重写系统自带的imageName:方法,这种方法虽然可以实现,但是它的弊端就是必须要使用自己的类,依赖性强。
2.给UIImage添加一个分类, 改变系统类的实现,给系统的类添加方法的时候调用(每次使用都需要导入头文件,并且如果项目比较大,之前使用的方法全部需要更改)。
3.使用runtime的交互方法,给系统的方法添加功能. 具体实现 : 添加一个分类 --> 在分类中提供一个自定义判空增加新功能的方法 --> 将这个方法的实现和系统自带的方法的实现交互.
le_imageNamed:和imageName:方法,达到调用le_imageNamed:其实就是调用imageNamed:方法的目的。
+ (void)load 方法里实现交换方法 (当程序启动的时候就会调用该方法,换句话说,只要程序一启动就会调用load方法,整个程序运行中只会调用一次)
•注意:交换方法时 le_imageNamed:方法中就不能再调用imageNamed:方法了,因为调用imageNamed:方法实质上相当于调用 le_imageNamed:方法,会循环引用造成死循环。
543627393 学习哦!
runtime—新手必学相关推荐
- python基础知识整理-整理了27个新手必学的Python基础知识点
原标题:整理了27个新手必学的Python基础知识点 1.执行脚本的两种方式 Python a.py 直接调用Python解释器执行文件 chomd +x a.py ./a.py #修改a.py文件的 ...
- python3.8.5怎么用-Python 3.8 新功能大揭秘【新手必学】
最新版本的Python发布了!今年夏天,Python 3.8发布beta版本,在2019年10月14日,第一个正式版本已准备就绪.现在,我们都可以开始使用新功能并从最新改进中受益. Python 3. ...
- python3.8怎么打开创建_Python 3.8 新功能大揭秘【新手必学】
最新版本的Python发布了!今年夏天,Python 3.8发布beta版本,在2019年10月14日,第一个正式版本已准备就绪.现在,我们都可以开始使用新功能并从最新改进中受益. Python 3. ...
- python桌面翻译_Python实现桌面翻译工具【新手必学】
Python 用了好长一段时间了,起初是基于对爬虫的兴趣而接触到的.随着不断的深入,慢慢的转了其它语言,毕竟工作机会真的太少了.很多技能长时间不去用,就会出现遗忘,也就有了整理一下,供初学者学习和讨论 ...
- 新手必学的几个视频剪辑技巧
在视频崛起的时代,B站和抖音等平台的视频都非常火爆,如果你还不会剪辑视频怎么办?今天小编给大家分享一些技巧,轻松上手,学会剪辑. 首先要给大家推的是一个新手和老手都必选的剪辑工具--视频剪辑高手,界面 ...
- 【前端工程化】配置package.json中scripts命令脚本,新手必学
每日鸡汤:你总要努力追上那个曾经被赋予众望的自己吧 目录 前言 一.运行npm run 命令之后会干啥? 1. scripts里面写啥 2. node_modules/.bin 二进制可执行文件 二. ...
- python爬虫模块取cookie_Python爬虫之cookie的获取、保存和使用【新手必学】
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:huhanghao Cookie,指某些网站为了辨别用户身份.进行s ...
- python编程规范 谷歌_Python最新编程规范,新手必学
最近,团队又来了几个小伙伴,经过一段时间磨合之后,发现彼此之间还是比较默契的,但有一个很大的问题是,每个人的编程风格和习惯都不同,导致现在代码看起来非常混乱. 这里还要注意:不管你是想学Python还 ...
- python 自动输入_Python自动输入【新手必学】
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:哈喽哈嘿哈 这篇文章是我的第一篇文章,写的不好的地方,请大家多多指教哈,另 ...
最新文章
- Facebook增强版LASER开源:零样本迁移学习,支持93种语言
- 从CPU缓存看缓存的套路
- Java:获取数组中的子数组的多种方法
- mysql forget the password
- C语言经典例19-完数
- 51nod 1770 数数字 找规律,注意进位,时间复杂度O(n)
- 终极会话劫持工具SSClone
- 如何使Mac Docker支持SQL on Linux容器Volume特性
- Django 遇到的错误:expected str, bytes or os.PathLike object, not _io.TextIOWrapper
- java 封装(Encapsulation)
- QCC3005 芯片开发过程中碰到的一些问题
- Q3面试嵌入式软件工程师的面试经验
- 容斥原理(转载http://www.cppblog.com/vici/archive/2011/09/05/155103.html)
- 一枚菜鸟前端工程师月度工作总结
- Ubuntu安装GIMP
- Android NDK-EGL 初级
- 前程似锦用计算机怎么表示,2021选什么专业 毕业后前程似锦
- 小米手机比较 联通、移动、电信 3G 支持比较
- 高德尝试用“成本价”推动共享,但高精地图行业不只有价格
- SPDY:一种更快速web的实验协议(转)
热门文章
- QTP中VBS脚本下FSO、WSH的应用(二)
- 6间房,把评论添加到视频的metadata.
- IE8中如何添加Activity
- 一天完成一点,进度太慢了啊
- 注解的原理又是怎么一回事
- 关于JFace中的向导式对话框(WizardDialog类)
- IOS之NSValue整理
- 一起谈.NET技术,HubbleDotNet 和 Lucene.Net 匹配相关度的比较
- DiskGenius的 “终止位置参数溢出”错误解决方法。
- Delphi 与 DirectX 之 DelphiX(80): TDIB.BlendPixel();