作为一门动态编程语言,Objective-C 会尽可能的将编译和链接时要做的事情推迟到运行时。只要有可能,Objective-C 总是使用动态 的方式来解决问题。这意味着 Objective-C 语言不仅需要一个编译环境,同时也需要一个运行时系统来执行编译好的代码。运行时系统(runtime)扮演的角色类似于 Objective-C 语言的操作系统,Objective-C 基于该系统来工作。因此,runtime好比Objective-C的灵魂,很多东西都是在这个基础上出现的。所以它是值的你花功夫去理解的。
我们将从以下几个方面了解Objective-C的运行时:
一、与静态语言编译后的区别
- 1、静态语言
一个静态语言程序,如下所示的C程序:123456#include < stdio.h > int main(int argc, const char **argv[]) { printf("Hello World!"); return 0; }
会经过编译器的语法分析,优化然后将你最佳化的代码翻译成汇编语言,然后完全按照你设计的逻辑和你的代码自上而下的执行。
- 2、Objective-C
很常见的一个消息发送语句:
|
|
会被编译器转化成
|
|
如果有参数则为
|
|
消息只有到运行时才会和函数实现绑定起来,而不是按照编译好的逻辑一成不变的执行。按照我的理解,编译阶段只是确定了要去向receiver对象发送message消息,但是却没有发送,真正发送是等到运行的时候进行。因此,编译阶段完全不知道message方法的具体实现,甚至,该方法到底有没有被实现也不知道。这就有可能导致运行时崩溃问题。
二、Objective-c
runtime的几点说明
- 1、runtime是开源的
是的,你没看错,runtime确实是开源的。目前苹果公司和GNU各自维护一个开源的runtime版本,这两个版本之间都在努力的保持一致。其中苹果的版本可以猛击该链接下载objc4-437.1.tar.gz
- 2、runtime是由C语言实现的
runtime做为Objective-C最核心的部分,几乎全部由C语言实现。这里的“几乎”所指的例外就包含有的方法(比如下面要说道的objc_msgSend方法)甚至是用汇编实现的!!
- 3、runtime的两个版本
Objective-C运行时系统有两个已知版本:早期版本(Legacy)和现行版本(Modern)。在现行版本中,最显著的新特性就是实例变量是”健壮“(non-fragile)的: 在早期版本中,如果您改变类中实例变量的布局,您必须重新编译该类的所有子类。 在现行版本中,如果您改变类中实例变量的布局,您无需重新编译该类的任何子类。此外,现行版本支持声明property的synthesis属性器。目前iPhone 程序和 Mac OS X v10.5 及以后的系统中的 64 位程序使用的都是 Objective-C 运行时系统的现行版 本。其它情况(Mac OS X 系统中的 32 位程序)使用的是早期版本。
三、和runtime ### system交互的三种方式
- 1、通过Objective-C源代码
大部分情况下,运行时系统在后台自动运行,我们只需编写和编译 Objective-C 源代码。当编译Objective-C类和方法时,编译器为实现语言动态特性将自动创建一些数据结构和函数。这些数据 结构包含类定义和协议类定义中的信息,如在Objective-C 2.0 程序设计语言中定义类和协议类一节所讨论 的类的对象和协议类的对象,方法选标,实例变量模板,以及其它来自于源代码的信息。运行时系统的主要功能就是根据源代码中的表达式发送消息。
- 2、通过类NSObject的方法
Cocoa程序中绝大部分类都是NSObject类的子类,所以大部分都继承了NSObject类的方法,因而继承 了NSObject的行为(NSProxy类是个例外)。然而,某些情况下, NSObject类仅仅定义了完成某件事情的模板,而没有提供所有需要的代码。例如,NSObject 类定义了description方法,返回该类内容的字符串表示。这主要是用来调试程序 ——GDB 中的 print-object 方法就是直接打印出该方法返回的字符串。NSObject 类中该方法的 实现并不知道子类中的内容,所以它只是返回类的名字和对象的地址。NSObject 的子类可以重新实现该方法以提供更多的信息。例如,NSArray 类改写了该方法来返回 NSArray 类包含的每个对象的内容。
某些 NSObject 的方法只是简单地从运行时系统中获得信息,从而允许对象进行一定程度的自我检查。
例如,class 返回对象的类;isKindOfClass:和 isMemberOfClass:则检查对象是否在指定的 类继承体系中;respondsToSelector:检查对象能否响应指定的消息;conformsToProtocol: 检查对象是否实现了指定协议类的方法;methodForSelector:则返回指定方法实现的地址。
- 3、通过运行时系统的函数