Swift之深入解析“类”的底层原理

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,主要用于区分是哪种类型的元数据;
	//******** TargetMetaData 定义 ********
	struct TargetMetaData{
    
    
	   using StoredPointer = typename Runtime: StoredPointer;
	    ...
	    
	    StoredPointer kind;
	}
	
	//******** Inprocess 定义 ********
	struct Inprocess{
    
    
	    ...
	    using StoredPointer = uintptr_t;
	    ...
	}
	
	//******** 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 {
    
    
	    // 匹配kind
	    switch (getKind()) {
    
    
	      // 如果kind是class
	    case MetadataKind::Class: {
    
    
	      // Native Swift class metadata is also the class object.
	      // 将当前指针强转为ClassMetadata类型
	      return static_cast<const ClassMetadata *>(this);
	    }
	    case MetadataKind::ObjCClassWrapper: {
    
    
	      // Objective-C class objects are referenced by their Swift metadata wrapper.
	      auto wrapper = static_cast<const ObjCClassWrapperMetadata *>(this);
	      return wrapper->Class;
	    }
	    // Other kinds of types don't have class objects.
	    default:
	      return nullptr;
	    }
	  }
  • 所以,TargetMetadata 和 TargetClassMetadata 本质上是一样的,因为在内存结构中,可以直接进行指针的转换,所以可以认为结构体,其实就是TargetClassMetadata;
  • 进入 TargetClassMetadata 定义,继承自 TargetAnyClassMetadata,有以下属性,这是类结构的组成部分:
template <typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
    
    
    ...
    // swift特有的标志
    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;//相当于OC中的isa,kind的实际类型是unsigned long
    void *superClass;
    void *cacheData;
    void *data;
    uint32_t flags; // 4字节
    uint32_t instanceAddressOffset;// 4字节
    uint32_t instanceSize;// 4字节
    uint16_t instanceAlignMask;// 2字节
    uint16_t reserved;// 2字节
    
    uint32_t classSize;// 4字节
    uint32_t classAddressOffset;// 4字节
    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 属性。

猜你喜欢

转载自blog.csdn.net/Forever_wj/article/details/112256567