You know, in Objective-C, the first 8 bytes of an object have an ISA pointer to its class object, which contains its object information, properties, member variable methods, etc., whereas in Swift, a pure Swift class, the first 8 bytes of the object point to HeapMetaData, HeapMetaData contains 8-16 bytes of memory management-related data.
Struct HeapMetadata {var Kind: Int var Superclass: Any.Type? var CacheData1: UnsafeRawPointer var CacheData2: UnsafeRawPointer var Data: Int var flags: Int32 var InstanceAddressPoint: UInt32 var InstanceSize: UInt32 var InstanceAlignMask: UInt16 var Reserved: UInt16 var ClassSize: UInt32 var ClassAddressPoint: UInt32 /// This attribute contains the class name and attribute information. UnsafePointer<TargetClassDescriptor> var IVarDestroyer: UnsafeRawPointer } struct TargetClassDescriptor { var Flags: UInt32; var Parent: Int32; Var Name: Int32; var Name: Int32; var AccessFunctionPtr: Int32; Var Fields: Int32 var SuperclassType: UInt32; /// Attribute information, which stores relative offset positions, of the type descriptor FieldDescriptor var Fields: Int32 var SuperclassType: UInt32; var MetadataNegativeSizeInWords: Int32 var MetadataPositiveSizeInWords: Int32 var NumImmediateMembers: Int32; var NumFields: Int32; var FieldOffsetVectorOffset: Int32; } struct FieldDescriptor {var MangledTypeName: Int32 var Superclass: Int32 Struct, enumeration or other var FieldDescriptorKind: FieldDescriptorKind var FieldRecordSize: Int16 var NumFields: Int32 // Attributes are not declared directly in the structure described by attributes; func fields(pointer: UnsafePointer<FieldDescriptor>) -> [FieldRecordPoint] { var fields = [FieldRecordPoint]() let base = unsafeBitCast(pointer + 1, to: UnsafePointer<FieldRecord>.self) for i in 0.. <self.NumFields { fields.append(FieldRecordPoint(pointer: base + Int(i))) } return fields } } struct FieldRecordPoint { var pointer: UnsafePointer<FieldRecord> var fieldRecordFlags: Int { return Int(pointer.pointee.fieldRecordFlags) } var mangledTypeName: String? { let address = Int(bitPattern: pointer) + 1 * 4 let offset = Int(pointer.pointee.mangledTypeNameOffset) if let cString = UnsafePointer<CChar>(bitPattern: address + offset) { return NSString(cString: cString, encoding: String.Encoding.utf8.rawValue) as? String } return nil } var fieldName: String { let address = Int(bitPattern: pointer) + 2 * 4 let offset = Int(pointer.pointee.fieldNameOffset) if let cString = UnsafePointer<UInt8>(bitPattern: address + offset) { return String(cString: CString)} return ""}} struct FieldRecord {/// struct FieldRecord {var fieldRecordFlags: UInt32 Offset of the attribute name var mangledTypeNameOffset: Int32 /// Offset of the attribute name var fieldNameOffset: Int32 func isVar() -> Bool { return fieldRecordFlags & 2 == 2 } func IsIndirectCase() -> Bool { return fieldRecordFlags & 1 == 1 } } enum FieldDescriptorKind : UInt16 { case Struct = 0 case Class case Enum case MultiPayloadEnum case `Protocol` case ClassProtocol case ObjCProtocol case ObjCClass }Copy the code
To verify this, create a class as follows
class TestClass {
var age: Int = 18
var name: String = "lkk"
}
Copy the code
You then get the type by converting it to get the class name and the property name and type
Let metadata = unsafeBitCast(testClass.self, To: UnsafePointer < HeapMetadata >. Self) / / / get the class Name in the Description information offset address let nameOffset = Int (metadata) pointee. Description. Pointee. Name) Let nameAddress = Int(bitPattern: Metadata. Pointee. Description) + 2 * 4 + nameOffset / / / through address access type let classNamePtr = UnsafePointer < CChar > (bitPattern: nameAddress) let name = NSString(cString: classNamePtr! , encoding: String.Encoding.utf8.rawValue) print(name!) / / / describe the information of attribute information of offset let fileOffset = Int (metadata) pointee. Description. Pointee. Fields) / / / calculate the attribute information of real address let fileAddress = Int(bitPattern: metadata.pointee.Description) + 4 * 4 + fileOffset let filePtr = UnsafePointer<FieldDescriptor>(bitPattern: FileAddress) let fileds = filePtr! .pointee.fields(pointer: filePtr!) for filed in fileds { let name = filed.fieldName if let cMangledTypeName = filed.mangledTypeName, / / / the filed by this method. The mangledTypeName into real information let fieldType = _getTypeByMangledNameInContext (cMangledTypeName, 256, genericContext: metadata.pointee.Description, genericArguments: metadata) { print("fieldName=\(name),fieldType=\(fieldType)") } } @_silgen_name("swift_getTypeByMangledNameInContext") public func _getTypeByMangledNameInContext( _ name: UnsafePointer<UInt8>, _ nameLength: Int, genericContext: UnsafeRawPointer? , genericArguments: UnsafeRawPointer?) -> Any.Type?Copy the code
The final print is as follows: