一个成熟的计算机语言必然有丰富的体系,复杂的容错机制,处理逻辑以及判断逻辑。但这些复杂的逻辑都是围绕一个主线丰富和展开的,所以在学习计算机语言的时候,先掌握核心,然后了解其原理,明白程序语言设计的实质和当时选择这种处理方式的原因是极其必要的,而且也是学习语言的捷径。

所以在学习的过程中,需要把握几个核心

先专注主线,后丰富周边;
先宏观了解,后微观精通;
多设身处地思考,理解代码设计的原因;
理解代码设计的原理和优化。

OC中处理方法的业务逻辑和其他语言不同,OC语言是动态语言(动态绑定,动态加载(dynamatic binding),动态类型)。其中动态加载就涉及到OC的运行时。在OC中,方法是动态实现的,调用方法实际就是在发送消息。

试想一下,一个方法的实现必然包含三个部分:

1.执行方法的对象
2.方法名称
3.不确定的参数

SEL只是一个方法名称IMP才是执行方法最终的函数,IMP包含这三个部分IMP 是一个函数指针,这个被指向的函数包含一个接收消息的对象 id(self 指针),调用方法的选标 SEL(方法名),以及不定个数的方法参数,并返回一个 id。也就是说 IMP 是消息最终调用的执行代码,是方法真正的实现代码 。

提问时间到了:

动态和静态有什么区别?

执行方法是怎么实现的?

OC的方法和C语言的函数原理一样么?

动态和静态有区别的。首先我们从最表层理解,一个方法的实现必然要包含执行者,方法名和不确定的参数和返回值。无论是静态或者动态方法都必须这三个必要元素(动态和静态的区别就在于在何时确定这些必要元素)。

方法的执行包含编译和运行两个过程。

静态方法是在编译时已经确定了三个要素,且不能更改。若类型不对,就会直接发出警告。

而OC的动态方法可以直接跳过编译,在运行时才开始添加函数调用,决定执行方法的三个要素。这就是动态方法(至于怎么执行,下面开始讲解)

这三个元素是如何确定的呢?首先我们看一段示例代码:

Dog *aDog = [[Dog alloc]init];
[aDog run];

在执行方法时,是怎么确定的呢?

此时我们需要注意OC内部方法的实质:OC中,方法实现实质就是发送消息。

[aDog run];代码的实质就是[ objc_sendMsg],它会找到执行方法的三个要素,找到就按照规则执行。

发送消息是通过 objc_send(id, SEL, ...) 来实现的,它首先会在对象的类对象的 cache,methodlist 以及父类对象的 cache,methodlist 中依次查找 SEL 对应 的 IMP,如果没有找到且实现了动态方法决议机制就会进行决议。

如果没有实现动态方法决议机制或决议失败且实现了消息转发机制就会进入消息转发流程,否则程序 crash。也就是说如果同时提供了动态方法决议和消息转发,那么动态方法决议先于消息转发,只有当动态方法决议依然无法正确决议 selector 的实现,才会尝试进行消息转发。当然,实际过程不可能那么简单,在开发语言之初,肯定会完善各种复杂场景和做了很多优化,接下来我们一起研究下OC对方法执行和扩展和优化:

第一步:先找方法

第二步:动态方法决议

第三部:消息转发

最后: 报错

消息转发

通常,给一个对象发送它不能处理的消息会得到出错提示,然而,Objective-C运行时系统在抛出错误之前,会给消息接收对象发送一条特别的消息 forwardInvocation 来通该对象,该消息的唯一参数是个 NSInvocation 类型的对象——该对象封装了原始的消息和消息的参数。我们可以实现 forwardInvocation,方法来对不能处理的消息做一些默认的处理,也可以将消息转发给其他对 象来处理,而不抛出错误。

1.首先去该类的方法cache中查找,如果找到了就返回它;

2.如果没有找到,就去该类的方法列表中查找。如果在该类的方法列表中找到了,则将 IMP 返回,并将 它加入 cache 中缓存起来。根据最近使用原则,这个方法再次调用的可能性很大,缓存起来可以节省下次 调用再次查找的开销;

3.如果在该类的方法列表中没找到对应的IMP,在通过该类结构中的super_class指针在其父类结构的方法列表中去查找,直到在某个父类的方法列表中找到对应的IMP,返回它,并加入cache中;

4.如果在自身以及所有父类的方法列表中都没有找到对应的 IMP,则看是不是可以进行动态方法决议(后面有专文讲述这个话题);

5.如果动态方法决议没能解决问题,进入下面要讲的消息转发流程。便利函数:我们可以通过 NSObject 的一些方法获取运行时信息或动态执行一些消息。

class 返回对象的类:

isKindOfClass,isMemberOfClass 检查对象是否在指定的类继承体系中;respondsToSelector 检查对象能否相应指定的消息;conformsToProtocol 检查对象是否实现了指定协议类的方法;methodForSelector 返回指定方法实现的地址;performSelector:withObject 执行 SEL 所指代的方法。

OC做为一门面向对象语言,自然具有面向对象的语言特性,如封装、继承、多态。他具有静态语言的特性(如C++),又有动态语言的效率(动态绑定、动态加载等)。整体来说,确实是一门不错的编程语言。

OC的动态语言特性

现在,让我来想想OC的动态语言特性。OC的动态特性表现为了三个方面:动态类型、动态绑定、动态加载。

之所以叫做动态,是因为必须到运行时(runtime)才会做一些事情。

(1)动态类型

动态类型,说简单点就是id类型。动态类型是跟静态类型相对的。像内置的明确的基本类型都属于静态类型(int、NSString等)。静态类型在编译的时候就能被识别出来。所以,若程序发生了类型不对应,编译器就会发出警告。而动态类型就编译器编译的时候是不能被识别的,要等到运行时(runtime),即程序运行的时候才会根据语境来识别。所以这里面就有两个概念要分清:编译时跟运行时。

(2)动态绑定

动态绑定(dynamic binding)貌似比较难记忆,但事实上很简单,只需记住关键词@selector/SEL即可。先来看看“函数”,对于其他一些静态语言,比如c++,一般在编译的时候就已经将将要调用的函数的函数签名都告诉编译器了。静态的,不能改变。而在OC中,其实是没有函数的概念的,我们叫“消息机制”,所谓的函数调用就是给对象发送一条消息。这时,动态绑定的特性就来了。OC可以先跳过编译,到运行的时候才动态地添加函数调用,在运行时才决定要调用什么方法,需要传什么参数进去。这就是动态绑定,要实现他就必须用SEL变量绑定一个方法。最终形成的这个SEL变量就代表一个方法的引用。这里要注意一点:SEL并不是C里面的函数指针,虽然很像,但真心不是函数指针。SEL变量只是一个整数,他是该方法的ID。以前的函数调用,是根据函数名,也就是字符串去查找函数体。但现在,我们是根据一个ID整数来查找方法,整数的查找字自然要比字符串的查找快得多!所以,动态绑定的特定不仅方便,而且效率更高。

(3)动态加载

动态加载就是根据需求动态地加载资源。我对动态加载比较陌生,所以就没什么可总结的啦。等以后慢慢完善。

转载于:https://www.cnblogs.com/fengmin/p/5599543.html

趣谈iOS运行时的方法调用原理相关推荐

  1. iOS运行时-使用Runtime向Category中添加属性以及运行时介绍

    前言 了解OC的都应该知道,在一般情况下,我们是不能向Category中添加属性的,只能添加方法,但有些情况向,我们确实需要向Category中添加属性,而且很多系统的API也有一些在Category ...

  2. objective-c 编程总结(第六篇)运行时操作 - 方法交换

    objective-c 编程总结(第六篇)运行时操作 - 方法交换 后面主要介绍oc类的运行时行为.这里面包括运行时方法的更换,消息的转发,以及动态属性.这些对于面向方面编程AOP的热爱者还是很有用的 ...

  3. 趣谈唯一邀请码生成方法

    趣谈唯一邀请码生成方法 前段时间项目上需要生成唯一邀请码!嘿嘿,多简单的一件事,心里就已默默将代码写了一遍.但小小的邀请码生成却也小有乾坤,这就是后话了. 一.最简单的实现 很多人 肯定都和我一开始一 ...

  4. java 字节码查看_一种查看java字节码时显示方法调用关系图的方法与流程

    本发明涉及一种代码逻辑分析方法,具体涉及一种查看java字节码时显示方法调用关系图的方法. 背景技术: 目前软件反编译领域有不少对可执行文件进行反编译的工具如IDA,也有对Java代码生成的中间码文件 ...

  5. 趣谈 iOS Universal Link

    作者:iHTCboy 本文对 iOS Universal Link(通用链接)的浅入浅出介绍,从产品的角度来了解其发展历程. 1.了解 Universal Link 背后的故事 2.学习 Univer ...

  6. java 程序运行时注入方法_Spring入门(九):运行时值注入

    Spring提供了2种方式在运行时注入值: 属性占位符(Property placeholder) Spring表达式语言(SpEL) 1. 属性占位符 1.1 注入外部的值 1.1.1 使用Envi ...

  7. 浅谈runtime运行时机制

    由于OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法.利用runtime机制让我们可以在程序运行时动态修改类.对象中的所有属性.方法. 下面就介绍运行时一种很简单的使 ...

  8. Windows驱动程序运行时函数的调用

    编译器厂商一般在发布其编译器的时候,会连同运行时函数一同发布.Windows驱动程序不能再代码中使用编译器提供的运行时函数,因为大部分运行时函数是基于Win32 API实现的,由于Win 32 API ...

  9. 【TS】1552- 浅谈TS运行时类型检查

    What-什么是运行时类型检查? 编译时类型检查(静态类型检查): 在编译阶段对变量类型进行静态检查,编译后的代码不保留任何类型标注信息,对实际代码运行没有影响 运行时类型检查(动态类型检查): 在代 ...

最新文章

  1. 第三波精品Android源码袭来!免费下载
  2. Java项目:干活管理系统(java+SSM+Jsp+Mysql)
  3. XML中CDATA及其字符实体的使用
  4. python2中如何得到一级域名
  5. 第一次走绿道,从长岭陂到梅林水库
  6. 上采样,下采样,过采样,欠采样的区别
  7. 交换机组播风暴_广播风暴的成因以及解决办法有哪些?
  8. SUSE上搭建Hadoop环境(单机模式+伪分布模式)
  9. create显示中文乱码 qt_Ubuntu下Qt串口助手接收中文乱码问题
  10. winxp系统的驱动可用于win2k吗?_收藏!工业机器人伺服系统常见问题汇总
  11. ​微信Android版支持改微信号,淘宝硬核拒绝改名要求;5G 套餐价格松动;Kotlin 1.4 第二个预览版发布|极客头条...
  12. 永远的动漫,梦想在,就有远方
  13. 强制删除文件处理程序
  14. Python中的角度转换功能
  15. 笔记本怎么设置WIfi热点
  16. IuCS IuPS IuR IuB Uu接口示意图
  17. JavaSE 多线程
  18. docker学习(八)深入浅出理解 dockerFille
  19. SA8155P QCOM 车载系统介绍
  20. 微博首席架构师杨卫华:新浪微博技术架构分析和InfoQ访谈

热门文章

  1. 关于C语言中 字符串常量的问题
  2. 详解DNS的常用记录(下):DNS系列之三
  3. java重定向带参数_急 求助重新封装重定向带参数问题
  4. JavaScript实时更新中国标准时间
  5. 优化营商环境建议个人_优化营商环境的几点建议(三)
  6. 关于 synchronizeOnSession
  7. Unity脚本生成插件:Script Create Dialog
  8. HDU 1431 素数回文
  9. easyui在IE中: SCRIPT1003: 缺少 ':'
  10. linux 模拟生成 CAN 设备