Objective-C runtime学习 – 上 – 瞎逼逼

34次阅读

共计 1708 个字符,预计需要花费 5 分钟才能阅读完成。

前言
入坑 iOS 开发已经一年半,对所学所用的知识却一直没有好好做梳理,这里梳理一下我对 Objective-C runtime 的学习和理解。
runtime 是 OC 这个语言的核心,想要弄明白 runtime,就不得不从语言设计层面开始说起,本篇主要讲讲这些宏观的东西,下篇再关注其实现细节与应用。
正文
20 世纪 80 年代,大家逐渐意识到在复杂系统开发和 GUI 编程中,面向对象编程有巨大的价值。由于当时 C 语言的广泛应用,一个比较直接的想法就是,在 C 语言的基础上扩展出面向对象能力,能够最大程度上减少开发者的迁移成本。于是 Objective- C 和 C ++ 都在这段时间里诞生了。
不过这两种语言在实现上都有着巨大的区别。Objective- C 选择使用 C 语言实现一套面向对象的库(我们称之为 Objective- C 的 runtime),并给 Objective- C 添加了一些面向对象的语法。编译时,Objective- C 的语法被处理为 C 的语法,然后和 runtime 库放到一起编译。因此,Objective- C 可以基于 runtime 实现一些动态特性,我的程序里打包了一个运行时系统嘛。而 C ++ 选择完全在编译期实现其面向对象特性。
这两种截然不同的实现,反映了设计者对语言动态特性的不同考量。其中最重要的一点是,对“面向对象”这一编程范式的理念不同。
面向对象思想意味着把程序抽象为各种独立而又互相调用的对象。在语言设计上,这里需要面对一个具体的问题,对象间的通信,应当是种什么形式?直觉上,对象间的通信,直接用方法调用的形式就好了。
世界上第一个面向对象的语言 Simula 就是这么实现的。但实际上会面临一些问题。具体来讲,当你调用一个对象的一个方法时,你怎么知道它有这个方法呢?这意味着你要确定这个对象的类型,也就是说,你必须先知道一个对象的类型才能对它进行调用。
在很多场景下,这种限制是不必要的。于是,世界上第二个面向对象的语言 Smalltalk 进行了一些改进,它实现了一套与目标对象无关的消息传递机制。消息的发送方可以不关注接收方的类型,也不关注接收方是否可以正常处理这条消息。而消息的接收方需要对收到的消息做处理,有对应的方法实现就去调用,没有就走异常处理流程。
C++ 传承了 Simula 的“静态消息机制”,而 Objective- C 传承了 Smalltalk 的“动态消息机制”。这两者的区别看似没那么大,却在很大程度上影响了之后面向对象体系的发展。
回到我们的 Objective-C,为了实现这种“动态消息机制”,通常需要一个运行时系统来处理。Objective- C 的发明者选择了最简单有效的方式,实现一套简单的运行时系统跟程序打包到一起。比起后来 Java 的虚拟机或 JavaScript 的执行引擎,Objective- C 的实现充分利用了原有的 C 编译器,只要给 Objective- C 做个预处理器,把 Objective- C 代码转成 C 代码然后和 runtime 库放一起用 C 的编译器编译就可以了,实现难度和工作量都是比较低的。此外,这样的实现保证了 Objective- C 跟 C 的完全兼容,可以说,Objective- C 代码在编译时就是 C 代码,因此可以和 C 或 C ++ 混编。
结语
总体而言,Objective- C 的语言设计至少在当时还是比较优越的。“动态消息机制”现在看来还是带来了一些好处的。而在 C 的基础上添加一个很薄的 runtime 层来为 C 提供面向对象机制,也是个很合适的做法。
后记
想要从宏观上理解清楚 Objective-C runtime 的来龙去脉,其实需要对整个面向对象的发展史有足够的理解,对面向对象的各种实现的优缺点有一定认知,显然我的能力是远远不够的。本文也只能简单梳理我个人的一点理解,可能还有颇多错漏。另外,Objective- C 的语言设计在当时有着不少优点的,但是 Objective- C 的语言发展已经停滞不前多年,比起一些热门的语言它在一定程度上是落后不少的,而苹果已经拥抱 swift,因此这种停滞可能是永久性的。

扩展阅读

function/bind 的救赎(上)——孟岩
C++ 多继承有什么坏处,Java 的接口为什么可以摈弃这些坏处?– invalid s 的回答 – 知乎

正文完
 0