程序员码农的世界iOS Developer

Objective-C Runtime 运行时一:从内存布局说起

2017-06-13  本文已影响1396人  蓝色小石头

本系列文章旨在简述iOS 中runtime为保障Objective-C动态特性所做的一些列操作,总体以Apple官方文档为基准,加以对其他大神文章的总结,以及笔者在学习使用过程中的一点点心得体会,尽量删繁就简只讲干货,尽量通俗易懂。水平有限,还望读者朋友们多多指正。

Objective-C Runtime 系列文章:

Objective-C Runtime 运行时一:内存布局

一、 Runtime使Objective-C成为一门动态语言

计算机只能直接理解机器语言,我们必须要把高级语言翻译成机器语言,才能执行高级语言编写的程序。编译,解释,两种方式只是翻译的时间不同。

Objective-C是编译型语言。

一般高级语言程序编译的过程:预处理、编译、汇编、链接。
一般高级语言(如C、C++)在编译、链接时就已经完成并确定程序的绝大多数决策,如类,类的属性、操作,方法的调用等,一切在程序编译完成之后运行之前都是清晰可见并确定的,这些事都需要一个好的编译器来完成(如gcc、clang)。

Objective-C总是尽可能地要把编译、链接阶段做的事放到运行时来做,显然编译器控制不到程序的运行阶段,这就是说还需要一个运行时系统(runtime system) 来执行编译后的代码。这就是 Objective-C Runtime 系统存在的意义,它是整个Objc运行框架的一块基石。

Runtime库主要做下面几件事:

二、 Runtime应用的时机及方式

Objective-C程序从三个层次与运行时系统交互:通过Objective-C源代码; 通过在Foundation框架的NSObject类中定义的方法; 并通过直接调用运行时函数。

1. Objective-C 源代码

runtime编译包含OC的类和方法的代码时,编译器会创建数据结构和函数来实现语言的动态特性。数据结构捕获类、类别、协议中的信息(变量、方法等)。runtime动态特性的核心功能就是发送消息。

在大多数情况下,运行时系统会自动运行并在幕后工作。您只需编写和编译Objective-C源代码就可以使用它。说白了就是runtime会根据需要在程序运行时自动插入runtime代码。

2. NSObject 的方法

Cocoa 中大多数类都是NSObject类的子类,也就继承了它的方法。最特殊的例外是NSProxy,它是个抽象超类,它实现了一些消息转发有关的方法,可以通过继承它来实现一个其他类的替身类或是虚拟出一个不存在的类,有时可用它来避免循环引用。

方法 作用
description 重载为你定义的类提供描述内容
isKindOfClass: 是否是当前类或其派生类成员
isMemberOfClass: 是否是当前类成员
respondsToSelector: 对象能否响应指定的消息
conformsToProtocol: 对象是否实现指定协议类的方法
methodForSelector: 返回指定方法实现的地址
3. Runtime 库函数

Runtime 系统是由一系列函数和数据结构组成,具有公共接口的动态共享库。头文件存放于/usr/include/objc目录下。许多函数允许你用纯C代码来重复实现 Objc 中同样的功能。虽然有一些方法构成了NSObject类的基础,但是你在写 Objc 代码时一般不会直接用到这些函数的,除非是写一些 Objc 与其他语言的桥接或是底层的debug工作。在Objective-C Runtime Reference中有对 Runtime 函数的详细文档。

说人话就是:

三、 类、对象、元类、类对象及内存布局

1. Class

Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。

//1. NSObject.h
@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}

//2. objc.h
typedef struct objc_class *Class;

objc_class结构体:

//3. objc/runtime.h
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
 
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父类
    const char *name                        OBJC2_UNAVAILABLE;  // 类名
    long version                            OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
    long info                               OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
    long instance_size                      OBJC2_UNAVAILABLE;  // 该类的实例变量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表
#endif
 
} OBJC2_UNAVAILABLE;
objc_class 变量名 作用
isa Objective-C中,所有的类自身也是一个对象,这个对象的Class里面也有一个isa指针,它指向metaClass(元类)
super_class 指向该类的父类,如果该类已经是最顶层的根类(如NSObjectNSProxy),则super_classNULL
cache 用于缓存最近使用的方法(类似于计算机中的高命中率缓存)
version 我们可以使用这个字段来提供类的版本信息。

2. id & objc_object

// usr/include/objc.h
/// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;

objc_object结构体有且只有一个字段:isa指针,指向对象所属的类。当创建一个特定类的实例对象时,分配的内存包含objc_object数据结构+类的实例变量的数据。NSObject类的allocallocWithZone:方法使用函数class_createInstance来创建objc_object数据结构.

id是一个objc_object结构类型的指针。类似于C++中的泛型。

3. Meta Class(元类)

所有的类自身也是一个对象,我们可以向这个对象发送静态消息(即调用类方法)。

即,任何NSObject继承体系下的meta-class都使用NSObjectmeta-class作为自己的所属类,而基类的meta-classisa指针是指向它自己。这样就形成了一个完美的闭环。

4. 内存布局

综上所述,再加上对objc_class结构体中super_class指针的分析(考虑父类的情况),我们就可以描绘出类及相应meta-class类的一个继承体系了,上一副经典的内存布局图。

OC内存布局(考虑父类)继承体系图.png

图实线是 super_class 指针,虚线是isa指针。

是不是又似懂非懂、似晕非晕了,没关系专业术语说完了,接下来说人话:

程序运行时,运行时系统通过自身的库函数在内存中(推测是代码区或静态区)为源代码中的每个类创建了类对象即meta-class(元类)的实例对象,类对象(类的代表)包含有类函数列表等。
如果我们要创建某个类的实例对象,对象的isa指针指向类对象(类的代表),类对象(类的代表)的isa指针指向根类(NSObject)的类对象(根类的代表),根类的isa指针指向根类的元类,而根类的元类是自身(NSObject)。 根元类的超类是NSObject,而isa指向了自己,而NSObject的超类为nil,也就是它没有超类。

也就是说,类对象是元类的实例,元类是根元类的实例,而根元类对象是自身的实例。类对象(即类)存储着一个类的所有实例方法,元类存储着一个类的所有类方法。

一个消息发送时:

这里未考虑父类存在的情况,详细内容后续文章单独介绍,敬请期待!!!

他山之石

本文特别感谢包括并不限于以下优秀文章:
Runtime奇技淫巧之类(Class)和对象(id)以及方法(SEL)
杨萧玉的博客(@杨萧玉HIT)

上一篇下一篇

猜你喜欢

热点阅读