Objective-C 类
熟练 OC 的一定对上面这张图不陌生,没错,这就是 Apple 官方的实例对象、类、元类关系图,形象地展示说明了 isa 的指向关系、superclass 的指向关系以及元类之间的继承关系;
看过 OC 类的实现原理,可以知道 OC 的类是从 objc_class 继承的,NSObject 是 OC 的类型, objc_object 是 c 的类型;
结构体类型 objc_class 继承于 objc_object 类型,其中 objc_object 也是一个结构体,且有一个 isa 属性,所以 objc_class 也拥有了 isa 属性;
NSObject 中的 isa 在底层是由 Class 定义的,其中 class 的底层编码来自 objc_class 类型,所以 NSObject 也拥有了 isa 属性;
NSObject 是一个类,用它初始化一个实例对象 objc ,objc 满足 objc_object 的特性(即有 isa 属性),主要是因为 isa 是由 NSObject 从 objc_class 继承过来的,而 objc_class 继承于 objc_object , objc_object 有 isa 属性。所以对象都有一个 isa,isa 表示指向来自于当前的 objc_object ;
objc_object 是当前的根对象,所有的对象都有这样一个特性 objc_object ,即拥有 isa 属性。
OC 的类的分析和探索,可以参考我之前的博客:iOS之深入解析类Class的底层原理 ;
那么 Swift 中的类是否也是这样呢?在 Swift 中类的结构是什么呢?它的底层实现又是怎么一回事呢?
类结构
一、结构组成
在上一篇博客中,我们分析了 Swift 的实例对象,对于实例对象来说,其本质是一个 HeapObject 结构体,默认 16 字节内存大小(有两个属性:metadata 8 字节 + refCounts 8 字节);
Swift 对象底层分析,请参考我的博客:Swift之深入解析对象的底层原理 ;
了解了 HeapObject 的内存分配之后,接下来应该注意到了⼀个 Metadata ,它的类型是 HeapMetadata,我们来看⼀下它的具体内存结构是什么?
二、HeapMetadata 类型分析
进入 HeapMetadata 定义,是 TargetHeapMetaData 类型的别名,接收了一个参数 Inprocess:
struct InProcess;
template < typename Target> struct TargetHeapMetadata;
using HeapMetadata = TargetHeapMetadata< InProcess> ;
#else
typedef struct HeapMetadata HeapMetadata;
typedef struct HeapObject HeapObject;
#endif
进入 TargetHeapMetaData 定义,其本质是一个模板类型,其中定义一些所需的数据结构。这个结构体中没有属性,只有初始化方法,传入了一个 MetadataKind 类型的参数,这里的 kind 就是传入的 Inprocess;
template < typename Runtime>
struct TargetHeapMetadata : TargetMetadata< Runtime> {
using HeaderType = TargetHeapMetadataHeader< Runtime> ;
TargetHeapMetadata ( ) = default ;
constexpr TargetHeapMetadata ( MetadataKind kind)
: TargetMetadata< Runtime> ( kind) {
}
#if SWIFT_OBJC_INTEROP
constexpr TargetHeapMetadata ( TargetAnyClassMetadata< Runtime> * isa)
: TargetMetadata< Runtime> ( isa) {
}
#endif
} ;
using HeapMetadata = TargetHeapMetadata< InProcess> ;
constexpr TargetHeapMetadata(MetadataKind kind) 就是初始化方法,其中 kind 的种类如下:
name
value
Class
0x0
Struct
0x200
Enum
0x201
Optional
0x202
ForeignClass
0x203
Opaque
0x300
Tuple
0x301
Function
0x302
Existential
0x303
Metatype
0x304
ObjCClassWrapper
0x305
ExistentialMetatype
0x306
HeapLocalVariable
0x400
HeapGenericLocalVariable
0x500
ErrorObject
0x501
LastEnumerated
0x7FF
进入 TargetMetaData 定义,有一个 kind 属性,kind 的类型就是之前传入的Inprocess。从这里可以得出,对于 kind,其类型就是 unsigned long,主要用于区分是哪种类型的元数据;
struct TargetMetaData{
using StoredPointer = typename Runtime: StoredPointer;
. . .
StoredPointer kind;
}
struct Inprocess{
. . .
using StoredPointer = uintptr_t;
. . .
}
typedef unsigned long uintptr_t;
从TargetHeapMetadata、TargetMetaData 定义中,可以看出初始化方法中参数kind 的类型是 MetadataKind;
进入 MetadataKind 定义,里面有一个#include “MetadataKind.def”,点击进入,其中记录所有类型的元数据;
回到 TargetMetaData 结构体定义中,找方法 getClassObject,在该方法中去匹配 kind 返回值是 TargetClassMetadata 类型;如果是 Class,则直接对this(当前指针,即metadata)强转为ClassMetadata;
const TargetClassMetadata< Runtime> * getClassObject ( ) const ;
template< > inline const ClassMetadata *
Metadata: : getClassObject ( ) const {
switch ( getKind ( ) ) {
case MetadataKind: : Class: {
return static_cast< const ClassMetadata * > ( this) ;
}
case MetadataKind: : ObjCClassWrapper: {
auto wrapper = static_cast< const ObjCClassWrapperMetadata * > ( this) ;
return wrapper-> Class;
}
default :
return nullptr;
}
}
所以,TargetMetadata 和 TargetClassMetadata 本质上是一样的,因为在内存结构中,可以直接进行指针的转换,所以可以认为结构体,其实就是TargetClassMetadata;
进入 TargetClassMetadata 定义,继承自 TargetAnyClassMetadata,有以下属性,这是类结构的组成部分:
template < typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata< Runtime> {
. . .
ClassFlags Flags;
uint32_t InstanceSize;
uint16_t InstanceAlignMask;
uint16_t Reserved;
uint32_t ClassSize;
uint32_t ClassAddressPoint;
. . .
}
进入 TargetAnyClassMetadata 定义,继承自 TargetHeapMetadata:
template < typename Runtime>
struct TargetAnyClassMetadata : public TargetHeapMetadata< Runtime> {
. . .
ConstTargetMetadataPointer< Runtime, swift: : TargetClassMetadata> Superclass;
TargetPointer< Runtime, void > CacheData[ 2 ] ;
StoredSize Data;
. . .
}
总结
一、Swift 类的构成
当 metadata 的 kind 为 Class 时,有如下继承链:
当前类返回的实际类型是 TargetClassMetadata,而 TargetMetaData 中只有一个属性 kind,TargetAnyClassMetaData 中有4个属性,分别是 kind,superclass,cacheData、data;
当前 Class 在内存中所存放的属性由 TargetClassMetadata 属性 + TargetAnyClassMetaData 属性 + TargetMetaData 属性构成,所以得出的 metadata的数据结构体如下所示:
struct swift_class_t: NSObject{
void * kind;
void * superClass;
void * cacheData;
void * data;
uint32_t flags;
uint32_t instanceAddressOffset;
uint32_t instanceSize;
uint16_t instanceAlignMask;
uint16_t reserved;
uint32_t classSize;
uint32_t classAddressOffset;
void * description;
. . .
}
二、Swift 类与 OC 类对比
OC 中的实例对象本质是结构体,是通过底层的 objc_object 创建,类是继承自objc_class;Swift 中的实例对象本质也是结构体,类型是 HeapObject,比 OC 多了一个 refCounts;
OC 中的方法存储在 objc_class 结构体 class_rw_t 的 methodList 中;swift 中的方法存储在 metadata 元数据中;
OC 中的 ARC 维护的是散列表;Swift 中的 ARC 是对象内部有 refCounts 属性。