博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS-类和对象之本质
阅读量:4135 次
发布时间:2019-05-25

本文共 4751 字,大约阅读时间需要 15 分钟。

iOS界比较流行的一句话:万物皆对象!为什么会有这么一个说法呢?难道类(class)也是对象(object)?对象其本质又是什么?这些问题在实际开发中或许遇不到,但当真的涉及到底层的开发,就要面对这些问题。想要透析对象的本质,就要了解运行时(runtime),苹果已经将 Object-C runtime 代码开源了,从: 浏览源代码。

1、类与对象的结构

首先在/usr/include/objc/objc.h文件中查看类(class)和对象(object)的定义:

/// An opaque type that represents an Objective-C class.typedef struct objc_class *Class;/// Represents an instance of a class.struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;};/// A pointer to an instance of a class.typedef struct objc_object *id;

由上面的源代码定义可以看出:

1、 Class (类)本质是 objc_class 结构类型的指针;

2、 objc_object (对象或类的实例)是包含一个Class类型的isa成员的结构体,isa是一个 objc_class 结构类型的指针,并指向对象的真实类型;
3、 id (任意对象) 本质是 objc_object 结构类型的指针,所以可以表示任意对象。

objc_object的结构我们知道了,那么objc_class的结构是怎样的?在runtime.h 文件中查看:

struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;#if !__OBJC2__ Class _Nullable super_class OBJC2_UNAVAILABLE; const char * _Nonnull name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;#endif} OBJC2_UNAVAILABLE;/* Use `Class` instead of `struct objc_class *` */

由上面源代码分析 objc_class 的各个成员:

isa:是一个 objc_class 结构类型的指针。isa指针指向一个类(元类),这个和objc_object的定义相似,既然有一个isa指针指向别的类,那么就可以把objc_class看成一个对象。引申为:任何以指向objc_class结构的指针(isa)开头的结构都可以视为objc_object! 类对象(class object)与实例对象(instance object)有什么区别?ObjC还对类对象与实例对象中的 isa 所指向的类结构作了不同的命名:类对象中的 isa 指向类结构被称作 metaClass(元类),metaClass 存储类的static类成员变量与static类成员方法(+开头的方法);实例对象中的 isa 指向类结构称作 class(普通的),class 结构存储类的普通成员变量与普通成员方法(-开头的方法)。

super_class:指向该类的父类,如果该类已经是最顶层的根类(如 NSObject ),那么 super_class 就为 NULL。

子类,父类,根类(这些都是普通 class)以及其对应的 metaClass 的 isa 与 super_class 之间关系,如下图:

在这里插入图片描述

翻译上图:
1、类的实例对象的 isa 指向该类;该类的 isa 指向该类的 metaClass;
2、类的 super_class 指向其父类,如果该类为根类则值为 NULL;
3、metaClass 的 isa 指向 metaClass,如果该 metaClass 是 metaclass 则指向自身;
4、metaClass 的 super_class 指向父 metaClass,如果该 metaClass 是 metaClass 则指向该 metaClass 对应的类;

Class 与 metaClass 的区别:

class 是 instance object 的类类型。当我们向实例对象发送消息(实例方法)时,我们在该实例对象的 class 结构的 cache或methodLists 中去查找响应的函数,如果没找到匹配的响应函数则在该 class 的父类中的 cache或methodLists 去查找(查找链为上图的中间那一排)。

如下面的代码中,向str 实例对象发送 lowercaseString 消息,会在 NSString 类结构的 cache或methodList 中去查找 lowercaseString 的响应函数。

NSString *str;[str lowercaseString];

metaClass 是 class object 的类类型。当我们向类对象发送消息(类方法)时,我们在该类对象的 metaclass 结构的 cache或methodLists 中去查找响应的函数,如果没有找到匹配的响应函数则在该 metaClass 的父类中的 cache或methodLists 去查找(查找链为上图的最右边那一排)。

如下面的代码中,向 NSString 类对象发送 stringWithString 消息,会在 NSString 的 metaClass 类结构的 cache或methodLists 中去查找 stringWithString 的响应函数。

[NSString stringWithString:@"string"];

运行时动态添加类源代码:

// Creates a new class and metaclass.Class _Nullableobjc_allocateClassPair(Class _Nullable superclass, const char * _Nonnull name,                        size_t extraBytes)

有上面源代码也可以看出,在运行期动态添加类时,会生成一个新的 class 和 metaclass。

name:一个 C 字符串,指示类的名称。我们可以在运行期,通过这个名称查找到该类以及该类的 metaClass

Class _Nullableobjc_getClass(const char * _Nonnull name)OBJC_EXPORT Class _Nullableobjc_getMetaClass(const char * _Nonnull name)

version:类的版本信息,默认初始化为 0。我们可以在运行期对其进行修改:

OBJC_EXPORT intclass_getVersion(Class _Nullable cls)OBJC_EXPORT voidclass_setVersion(Class _Nullable cls, int version)

info:供运行期使用的一些位标识。有如下一些位掩码:

CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含实例方法和变量;
CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法;
CLS_INITIALIZED (0x4L) 表示该类已经被运行期初始化了,这个标识位只被 objc_addClass 所设置;
CLS_POSING (0x8L) 表示该类被 pose 成其他的类;(poseclass 在ObjC 2.0中被废弃了);
CLS_MAPPED (0x10L) 为ObjC运行期所使用
CLS_FLUSH_CACHE (0x20L) 为ObjC运行期所使用
CLS_GROW_CACHE (0x40L) 为ObjC运行期所使用
CLS_NEED_BIND (0x80L) 为ObjC运行期所使用
CLS_METHOD_ARRAY (0x100L) 该标志位指示 methodLists 是指向一个 objc_method_list 还是一个包含 objc_method_list 指针的数组;

instance_size:该类的实例变量大小(包括从父类继承下来的实例变量);

ivars:指向 objc_ivar_list 的指针,存储每个实例变量的内存地址,如果该类没有任何实例变量则为 NULL;

methodLists:与 info 的一些标志位有关,CLS_METHOD_ARRAY 标识位决定其指向的东西(是指向单个 objc_method_list还是一个 objc_method_list 指针数组),如果 info 设置了 CLS_CLASS 则 objc_method_list 存储实例方法,如果设置的是 CLS_META 则存储类方法;

cache:指向 objc_cache 的指针,用来缓存最近使用的方法,以提高效率;

protocols:指向 objc_protocol_list 的指针,存储该类声明要遵守的正式协议。

总结:

类的的本质是 objc_class 结构类型的指针;对象定义上是一个结构体,其本质是一个objc_class 结构类型的指针(isa);任何以objc_class 结构的指针开头的结构都可以看成一个对象,即类也可以看作是一个对象;对象分为类对象和实例对象,类对象中的isa指针指向metaClass,metaClass 存储类成员变量与类成员方法;实例对象中的isa指针指向该实例对象的类型,存储类的普通成员变量与普通成员方法。

参考:

1、

2、
3、

转载地址:http://ngivi.baihongyu.com/

你可能感兴趣的文章
如何实现a===1 && a===2 && a===3返回true?
查看>>
49个在工作中常用且容易遗忘的CSS样式清单整理
查看>>
20种在学习编程的同时也可以在线赚钱的方法
查看>>
隐藏搜索框:CSS 动画正反向序列
查看>>
12 个JavaScript 特性技巧你可能从未使用过
查看>>
127个超级实用的JavaScript 代码片段,你千万要收藏好(上)
查看>>
【视频教程】Javascript ES6 教程27—ES6 构建一个Promise
查看>>
【5分钟代码练习】01—导航栏鼠标悬停效果的实现
查看>>
127个超级实用的JavaScript 代码片段,你千万要收藏好(中)
查看>>
8种ES6中扩展运算符的用法
查看>>
【视频教程】Javascript ES6 教程28—ES6 Promise 实例应用
查看>>
127个超级实用的JavaScript 代码片段,你千万要收藏好(下)
查看>>
【web素材】03-24款后台管理系统网站模板
查看>>
Flex 布局教程:语法篇
查看>>
年薪50万+的90后程序员都经历了什么?
查看>>
2019年哪些外快收入可达到2万以上?
查看>>
【JavaScript 教程】标准库—Date 对象
查看>>
前阿里手淘前端负责人@winter:前端人如何保持竞争力?
查看>>
【JavaScript 教程】面向对象编程——实例对象与 new 命令
查看>>
我在网易做了6年前端,想给求职者4条建议
查看>>