众所周知,Objective-C 是一种运行时语言。运行时怎么来体现的呢?比如一个对象的类型确定,或者对象的方法实现的绑定都是推迟到软件的运行时才能确定的。而运行时的诸多特性都是由Runtime 来实现的。

Runtime 其实就是一套C语言API库,因此它的实现也还是C语言。如果你想看Runtime的实现源码,可以去官网下载:objc4-646.tar.gz(我看的是这个)。

本篇不打算介绍objc_msgSend,但是关于OC中的消息最终怎么被转化为objc_msgSend这个过程,还是有必要找一篇文章好好的看一下。

以下内容部分摘录自:

王巍 (@onevcat) 的 深入Objective-C的动态特性

Bang 的如何动态调用 C 函数

如果你觉得看的不尽兴,可以去看下这两篇文章。

动态特性

在开始介绍runtime 之前,先讲讲动态特性。经常被提到和用到的有三种:

* 动态类型(Dynamic typing)

* 动态绑定(Dynamic binding)

* 动态加载(Dynamic loading)

动态加载

先来说说* 动态加载 * ,动态加载就是根据需求加载所需要的资源。有一个典型的例子,就是iPhone 会根据机型的不同加载不同的图片。iOS 下一般会有xxx.png、xxx@2x.png、xxx@3x.png。iOS 应用会在非retina设备上加载1倍图,在retina小尺寸设备(如4、4s、5、5c、5s、6、6s)上加载@2x图片,然后在大屏retina 设备(如6+、6s+)上加载@3x的图片。

动态类型

然后再来说说* 动态类型 *,即运行时再决定对象的类型。动态类型这个特性在日常开发中非常的常见,最简单的就是id类型。稍微常用的就是某个类和其自行的类型确定。id类型即通用的对象类,任何对象都可以被id指针所指,而在实际使用中,往往使用introspection来确定该对象的实际所属类:

id obj = someInstance;
if ([obj isKindOfClass:someClass])
{
someClass *classSpecifiedInstance = (someClass *)obj;
// Do Something to classSpecifiedInstance which now is an instance of someClass
//...
}

-isMemberOfClass:NSObject的方法,用以确定某个 NSObject对象是否是某个类的成员。与之相似的为 -isKindOfClass:,可以用以确定某个对象是否是某个类或其子类的成员。这两个方法为典型的introspection方法。在确定对象为某类成员后,可以安全地进行强制转换,继续之后的工作。

动态类型有利有弊,有了动态类型,我们可以在运行时根据对象的类型不同执行不同的逻辑代码;但是也导致一些错误不能及时的发现。

比如,我们经常会遇到的这类错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_NSZeroData count]: unrecognized selector sent to instance 0x7f8632ed7ab0'

这是错误的示例代码:



这就是我们错误的将一个NSData 对象赋值给了NSArray 实例,然后又调用数组的count 方法。在2014 年以前,并不会出现这样的警告信息,所以那时候很容易出现类似这样的错误。随着Swift 的推出,OC 中也加入了类型检查。现在我们就可以很及时的减少这类错误的产生。

动态绑定

基于动态类型,在某个实例对象被确定后,其类型便被确定了。该对象对应的属性和响应的消息也被完全确定,这就是动态绑定。在继续之前,需要明确Objective-C中消息的概念。由于OC的动态特性,在OC中其实很少提及“函数”的概念,传统的函数一般在编译时就已经把参数信息和函数实现打包到编译后的源码中了,而在OC中最常使用的是消息机制。调用一个实例的方法,所做的是向该实例的指针发送消息,实例在收到消息后,从自身的实现中寻找响应这条消息的方法。

关于传统的函数编译时,把参数信息和函数打包进编译后的源码,以及调用过程,可以参看:Bang的如何动态调用 C 函数

OC 的编译过程之所以不一样,是因为在汇编过程,被苹果自己写的汇编接管了。

动态绑定所做的,即是在实例所属类确定后,将某些属性和相应的方法绑定到实例上。这里所指的属性和方法当然包括了原来没有在类中实现的,而是在运行时才需要的新加入的实现。在Cocoa层,我们一般向一个NSObject对象发送-respondsToSelector:或者-instancesRespondToSelector:等来确定对象是否可以对某个SEL做出响应,而在OC消息转发机制被触发之前,对应的类的+resolveClassMethod:和+resolveInstanceMethod:将会被调用,在此时有机会动态地向类或者实例添加新的方法,也即类的实现是可以动态绑定的。一个例子:

void dynamicMethodIMP(id self, SEL _cmd)
{
// implementation ....
} //该方法在OC消息转发生效前被调用
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{
if (aSEL == @selector(resolveThisMethodDynamically)) {
//向[self class]中新加入返回为void的实现,SEL名字为aSEL,实现的具体内容为dynamicMethodIMP class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, “v@:”);
return YES;
}
return [super resolveInstanceMethod:aSel];
}

当然也可以在任意需要的地方调用class_addMethodmethod_setImplementation(前者添加实现,后者替换实现),来完成动态绑定的需求。

关于动态绑定,我的理解例子是:

假设程序里有Person这么一个类,它有name、age、height 以及方法-eat(假设除name、age、height 和-eat 外,其他的属性和方法忽略),然后我们在某处创建了Person这个实例对象。



如果这里理解的有误,欢迎指正。

刚开始这个实例对象就像白纸一样干净,不知道它的具体类型,也没有属性和方法。然后在动态类型阶段,确定它的实际类型。再经过动态绑定,才会为其绑定相应的属性和方法,这时候这个对象才算完整了。

关于runtime 的一些基础知识就先到这里了。

Runtime系列(一)-- 基础知识的更多相关文章

  1. MySQL系列(一)--基础知识(转载)

    安装就不说了,网上多得是,我的MySQL是8.0版本,可以参考:CentOS7安装MySQL8.0图文教程和MySQL8.0本地访问设置为远程访问权限 我的MySQL安装在阿里云上面,阿里云向外暴露端 ...

  2. 1 python大数据挖掘系列之基础知识入门

    preface Python在大数据行业非常火爆近两年,as a pythonic,所以也得涉足下大数据分析,下面就聊聊它们. Python数据分析与挖掘技术概述 所谓数据分析,即对已知的数据进行分析 ...

  3. 3.Swift翻译教程系列——Swift基础知识

    英语PDF下载链接http://download.csdn.net/detail/tsingheng/7480427 Swift是用来开发iOS和OS X应用的新语言,可是很多地方用起来跟C或者OC是 ...

  4. EJB系列 - EJB基础知识

    本人博客文章网址:https://www.peretang.com/basic-knowledge-of-ejb/ 什么是EJB 可移植的, 可重用的, 可伸缩的业务应用程序的平台 为什么选择EJB ...

  5. python大数据挖掘系列之基础知识入门

    preface Python在大数据行业非常火爆近两年,as a pythonic,所以也得涉足下大数据分析,下面就聊聊它们. Python数据分析与挖掘技术概述 所谓数据分析,即对已知的数据进行分析 ...

  6. C++ 系列:基础知识储备

    Copyright © 2000-2017, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ ----------------- ...

  7. 《吊打面试官》系列-Redis基础知识

    前言Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难.作为一个在互联网公司面一次拿一次offer的面霸(请允许我使用一下 ...

  8. 【Git 系列】基础知识全集

    Git 是一种分布式版本控制系统,它可以不受网络连接的限制,加上其它众多优点,目前已经成为程序开发人员做项目版本管理时的首选,非开发人员也可以用 Git 来做自己的文档版本管理工具. 一.Git 基础 ...

  9. 玩耍Hibernate系列(二)--基础知识

    Hibernate思维导图   Hibernate映射 关于hibernate的映射要说明的一点就是关于ID的访问权限,peroperty以及field的区别: 表的主键在内存中对应一个OID对象描述 ...

  10. 玩耍Hibernate系列(一)--基础知识

    Hibernate框架介绍: Hibernate  ORM  主要用于持久化对象(最常用的框架) Hibernate  Search 用于对对象进行搜索,底层基于Apache Lucene做的 Hib ...

随机推荐

  1. 【bzoj4008 hnoi2015】 亚瑟王

    题目描述 小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑.他决定,在脱坑之前,最后再来打一盘亚瑟王.既然是最后一战,就一定要打得漂亮.众所周知,亚瑟王是一个看脸的游戏,技能 ...

  2. 【iOS】苹果开发者账号申请

    [1]首先登陆苹果开发者中心:https://developer.apple.com/programs/ 如图有一个按钮enroll,意思是苹果开发者报名(说白了就是要交钱,好让你具备APP测试和上线 ...

  3. java线程池的使用

    一.简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后加入了java.uti ...

  4. JVM程序计数器

    一.先来看看概念 多线程的Java应用程序:为了让每个线程正常工作就提出了程序计数器(Programe Counter Register),每个线程都有自己的程序计数器这样当线程执行切换的时候就可以在 ...

  5. mysql获取某个表的所有字段名

    http://www.netingcn.com/mysql-column-name.html mysql安装成功后可以看到已经存在mysql.information_schema和test这个几个数据 ...

  6. 阻止Enter键回发到服务端Asp.net

    //阻止enter键回发到服务端$(function () {    $("input[type=text]").each(function () {        $(this) ...

  7. MongoDB 条件操作符

    描述 条件操作符用于比较两个表达式并从mongoDB集合中获取数据. 在本章节中,我们将讨论如何在MongoDB中使用条件操作符. MongoDB中条件操作符有: (>) 大于 - $gt (& ...

  8. windows下python3.5使用pip离线安装whl包

    0. 绪论 Windows离线断网环境下安装Python包,配置环境,准备用来生成word模版.姑且记录一下 生产环境 : windows 7 windows10 python 3.5.2 pip 1 ...

  9. 使用GDB调试STL容器

    GDB中print方法并不能直接打印STL容器中保存的变量,想知道STL容器保存的变量,使用如下办法: 1. 创建文件~/.gdbinit: # # STL GDB evaluators/views/ ...

  10. Android studio 中引用jar的其实是Maven?(一)

    由于Studio比eclipse多了一步对工程构建的步骤,即为build.gradle这个文件运行,因此其引入第三方开发jar包与lib工程对比Eclipse已完成不同,引入第三方jar与lib工程显 ...