Swift's in-depth analysis of the underlying principle of "class"

Objective-C class

Insert picture description here

  • Those who are proficient in OC must be familiar with the above picture. Yes, this is Apple’s official instance object, class, and metaclass relationship diagram. It vividly shows the relationship between isa, superclass, and metaclass. Inheritance relationship
  • Having seen the implementation principle of the OC class, we can know that the OC class is inherited from objc_class, NSObject is the type of OC, and objc_object is the type of c;
  • The structure type objc_class inherits from the objc_object type, where objc_object is also a structure and has an isa attribute, so objc_class also has an isa attribute;
  • The isa in NSObject is defined by Class at the bottom, and the bottom code of class comes from the objc_class type, so NSObject also has the isa attribute;
  • NSObject is a class, use it to initialize an instance object objc, objc satisfies the characteristics of objc_object (that is, has isa attribute), mainly because isa is inherited from objc_class by NSObject, and objc_class inherits from objc_object, and objc_object has isa attribute. So the object has an isa, which means that it points to the current objc_object;
  • objc_object is the current root object, all objects have such a characteristic objc_object, that is, have the isa attribute.
  • For the analysis and exploration of OC classes, please refer to my previous blog: iOS in-depth analysis of the underlying principles of class classes ;
  • So is the same with classes in Swift? What is the structure of a class in Swift? What about its underlying implementation?
Class structure
1. Structure
  • In the previous blog, we analyzed the instance object of Swift. For instance objects, its essence is a HeapObject structure with a default memory size of 16 bytes (there are two attributes: metadata 8 bytes + refCounts 8 bytes );
  • Swift object analysis, please refer to my blog: Swift's in-depth analysis of the underlying principles of objects ;
  • After understanding the memory allocation of HeapObject, you should notice a Metadata. Its type is HeapMetadata. Let’s take a look at its specific memory structure.
Two, HeapMetadata type analysis
  • Enter the HeapMetadata definition, which is an alias of TargetHeapMetaData type, and receives a parameter Inprocess:
	struct InProcess;
	
	template <typename Target> struct TargetHeapMetadata;
	using HeapMetadata = TargetHeapMetadata<InProcess>;
	#else
	typedef struct HeapMetadata HeapMetadata;
	typedef struct HeapObject HeapObject;
	#endif
  • Enter TargetHeapMetaData definition, which is essentially a template type, which defines some required data structures. There are no attributes in this structure, only the initialization method, and a parameter of MetadataKind type is passed in, where kind is the passed 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) is the initialization method, and the types of kind are as follows:
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
  • Enter TargetMetaData definition, there is a kind attribute, the type of kind is the previously passed Inprocess. It can be concluded from this that for kind, its type is unsigned long, which is mainly used to distinguish which type of metadata;
	//******** TargetMetaData 定义 ********
	struct TargetMetaData{
    
    
	   using StoredPointer = typename Runtime: StoredPointer;
	    ...
	    
	    StoredPointer kind;
	}
	
	//******** Inprocess 定义 ********
	struct Inprocess{
    
    
	    ...
	    using StoredPointer = uintptr_t;
	    ...
	}
	
	//******** uintptr_t 定义 ********
	typedef unsigned long uintptr_t;
  • From the definition of TargetHeapMetadata and TargetMetaData, it can be seen that the type of the parameter kind in the initialization method is MetadataKind;
    • Enter the MetadataKind definition, there is a #include "MetadataKind.def", click to enter, which records all types of metadata;
    • Go back to the TargetMetaData structure definition, find the method getClassObject, in this method to match kind, the return value is TargetClassMetadata type; if it is Class, directly force this (the current pointer, that is metadata) to 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;
	    }
	  }
  • Therefore, TargetMetadata and TargetClassMetadata are essentially the same, because in the memory structure, pointers can be converted directly, so it can be considered that the structure is actually TargetClassMetadata;
  • Enter TargetClassMetadata definition, inherited from TargetAnyClassMetadata, have the following attributes, which are part of the class structure:
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;
  ...
}
  • Enter TargetAnyClassMetadata definition, inherited from TargetHeapMetadata:
template <typename Runtime>
struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
    
    
    ...
    ConstTargetMetadataPointer<Runtime, swift::TargetClassMetadata> Superclass;
    TargetPointer<Runtime, void> CacheData[2];
    StoredSize Data;
    ...
}
to sum up
1. The composition of Swift class
  • When the kind of metadata is Class, there is the following inheritance chain:
    Insert picture description here
  • The actual type returned by the current class is TargetClassMetadata, and there is only one attribute kind in TargetMetaData, and there are 4 attributes in TargetAnyClassMetaData, namely kind, superclass, cacheData, and data;
  • The attributes of the current Class stored in memory are composed of TargetClassMetadata attribute + TargetAnyClassMetaData attribute + TargetMetaData attribute, so the resulting metadata structure is as follows:
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;
    ...
}
2. Comparison of Swift class and OC class
  • The instance object in OC is essentially a structure, which is created through the underlying objc_object, and the class is inherited from objc_class; the instance object in Swift is also a structure in nature, the type is HeapObject, which has one more refCounts than OC;
  • The methods in OC are stored in the methodList of the objc_class structure class_rw_t; the methods in swift are stored in metadata;
  • ARC in OC maintains a hash table; ARC in Swift has refCounts property inside the object.

Guess you like

Origin blog.csdn.net/Forever_wj/article/details/112256567