Swift探索(六): Mirror源碼解析

一:元類型和 .self

1. AnyObject

AnyObject 代表任意類的實(shí)例,類的類型担忧,僅類遵守的協(xié)議芹缔。

class Person {
    var age: Int = 18
    var name: String = "小明"
}

var p = Person()

var p1: AnyObject = p

var p2: AnyObject = Person.self

AnyObject.png

AnyObject匯編.png

可以看見 p1AnyObject 表示的就是一個(gè)實(shí)例對(duì)象,p2AnyObject 表示的就是原類型 Metadata

protocol Myprotocol: AnyObject {

}

class Person: Myprotocol {
    var age: Int = 18
    var name: String = "小明"
}

var p: Myprotocol = Person()

var p1: AnyObject = p

struct protocol.png

此時(shí)的協(xié)議 Myprotocol 后面的 AnyObject 就表示的遵守的協(xié)議瓶盛,如果將 Class 換成 Struct 編譯器就會(huì)報(bào)錯(cuò)最欠,因此 AnyObject 是能代表僅類遵守的協(xié)議。

在編寫代碼的過程中惩猫,有時(shí)候不知道具體的類型芝硬,用 AnyObject 來表示

class Person {
    var age: Int = 18
    var name: String = "小明"
}

var p = Person()

var a: AnyObject = p.age as NSNumber

print(type(of: a))

// 打印結(jié)果
__NSCFNumber

如果確定了類型,使用三個(gè)關(guān)鍵字將 AnyObject 轉(zhuǎn)換成具體的類型 as 轧房、 as? 拌阴、 as!

class Person {
    var age: Int = 18
    var name: String = "小明"
}

class SubPerson: Person {
    var height: Double = 185.5
}

var p: AnyObject = SubPerson()

if let p1 = p as? Person {
    print("\(p1) 是 Person")
}

// 打印結(jié)果
LJLSwiftSimpleTest.SubPerson 是 Person

2. T.self

class Person {
    var age: Int = 18
    var name: String = "小明"
}

var p = Person()

var p1 = p.self

var p2 = p.self.self

var p3 = Person.self

T.self.png

T.self匯編.png

從上面打印結(jié)果和在匯編中的打印結(jié)果可以看出:
T 是實(shí)例對(duì)象,則 T.self 返回的就是他本身奶镶, T 是類迟赃,則 T.self 返回的就是元類型

class Person {
    var age: Int = 18
    var name: String = "小明"
    
    func test() {
        // self只當(dāng)前實(shí)例對(duì)象
        print(self)
    }
    
    // 類方法
    static func test1() {
        // self 是 Person 這個(gè)類型本身
        print(self)
    }
}

var p = Person()
p.test()
Person.test1()

self.png

在第一個(gè)斷點(diǎn)處打印 self 得到當(dāng)前實(shí)例對(duì)象,在第二個(gè)斷點(diǎn)處打印 self 得到 Person 類本身厂镇。

3. Self

Self 類型不是特定的類型纤壁,而是方便地引用當(dāng)前類型,而無需重復(fù)或知道該類型的名稱剪撬。

  • 作為方法返回類型:Self 指代當(dāng)前實(shí)例對(duì)象的類型
class Person {
    static let age = 18
    func test() -> Self{
        return self
    }
}
  • 作為協(xié)議中方法的返回類型:Self 指代遵循這個(gè)協(xié)議的類型
protocol MyProtocol {
    func get() -> Self
}

class Person: MyProtocol {
    func get() -> Self {
        return self
    }
}

4. Any

Any 代表任意類型摄乒,包括 function 類型或者 Optional 類型

var array: [Any] = [1, "小明", 3, false]

這里不能替換成 AnyObject ,因?yàn)?Int 類型在 Swift 中是值類型,無法用 AnyObject 表示

5. AnyClass

AnyClass 代表任意實(shí)例的類型

AnyClass.png

可以看到 AnyClass 就是 AnyObjectType 類型

class Person {
    var age = 18
}

var t: AnyClass = Person.self

T.TypeT.self 的類型

二:Swift Runtime

我們都知道 Swift 是一門靜態(tài)語言馍佑,但是在之前的文章 Swift探索(二): 類與結(jié)構(gòu)體(下) 中提過 @objc 斋否、NSObject@Objc dynamic 標(biāo)識(shí)拭荤。那么是可以通過這些關(guān)鍵字來實(shí)現(xiàn)在 Swift中調(diào)用 OCRuntimeAPI 的茵臭。

func test(_ cls: AnyClass){
    var methodCount: UInt32 = 0
    let methodlist = class_copyMethodList(cls, &methodCount)
    for  i in 0..<numericCast(methodCount) {
        if let method = methodlist?[i]{
            let methodName = method_getName(method)
            print("方法列表 :\(String(describing: methodName))")
        } else{
            print("not found method")
        }
    }
    var count: UInt32 = 0
    let proList = class_copyPropertyList(cls, &count)
    for  i in 0..<numericCast(count) {
        if let property = proList?[i] {
            let propertyName = property_getName(property)
            print("屬性成員屬性:\(String(utf8String: propertyName)!)")
        } else {
            print("not fount property")
        }
    }
}

使用以上代碼獲取一個(gè)類的屬性和方法

class Person {
    var age: Int = 18
    func play() {
        print("play")
    }
}

test(Person.self)

// 打印結(jié)果
空
  • 對(duì)于純 Swift 類來說,方法和屬性不加任何修飾符時(shí)舅世。不具備 Runtime 特性旦委。
class Person {
    @objc var age: Int = 18
    @objc func play() {
        print("play")
    }
}

test(Person.self)

// 打印結(jié)果
方法列表 :play
方法列表 :age
方法列表 :setAge:
屬性成員屬性:age
添加@objc.png
  • 對(duì)于純 Swift 類,方法和屬性添加 @objc 標(biāo)識(shí)時(shí)雏亚,可以用過 RunTimeApi 拿到缨硝,但在 OC 中無法進(jìn)行調(diào)度( LJLSwiftSimpleTest-Swift.h 中沒有任何 Person 這個(gè)信息)。
class Person: NSObject {
    var age: Int = 18
    func play() {
        print("play")
    }
}

test(Person.self)

// 打印結(jié)果
方法列表 :init

class Person: NSObject {
    @objc var age: Int = 18
    @objc func play() {
        print("play")
    }
}

test(Person.self)

// 打印結(jié)果
方法列表 :init
方法列表 :play
方法列表 :age
方法列表 :setAge:
屬性成員屬性:age
  • 對(duì)于繼承自 NSObjectSwift 類罢低,必須在聲明屬性和方法前添加 @objc 關(guān)鍵字才能動(dòng)態(tài)的獲取當(dāng)前的屬性和方法查辩。
class Person {
    dynamic var age: Int = 18
    dynamic func play() {
        print("play")
    }
}

extension Person {
    @_dynamicReplacement(for: play) // 用play1()替代play()函數(shù)
    func play1() {
        print("play1")
    }
}

Person().play()
  • Swfit 沒有動(dòng)態(tài)性,但方法网持、屬性前添加 dynamic 關(guān)鍵字宜岛,可獲得動(dòng)態(tài)性
class Person: NSObject {
    var age: Int = 18
    func play() {
        print("play")
    }
}

class SubPerson: Person {
    dynamic var name: String = "小明"
    dynamic func play2() {
        print("play2")
    }
}

  • 繼承自 NSObjectSwift 類,其繼承自父類的方法具有動(dòng)態(tài)性功舀,其它自定義方法萍倡、屬性相應(yīng)獲得動(dòng)態(tài)性,需要添加 dynamic 修飾
    image.png
  • 若方法的參數(shù)辟汰、屬性類型為 Swfit 特有無法映射到 OC的類型(如 Character 列敲、 Tuple ),則此方法莉擒、屬性無法添加 @objcdynamic 關(guān)鍵字(編譯器報(bào)錯(cuò))

三:Mirror

1. Mirror的基本用法

反射:就是動(dòng)態(tài)獲取類型酿炸、成員信息、在運(yùn)行時(shí)可以調(diào)用方法涨冀、屬性等行為的特性填硕。
Swift 的反射機(jī)制是基于 Mirror 的結(jié)構(gòu)體來實(shí)現(xiàn)的÷贡睿可以為具體的實(shí)例創(chuàng)建一個(gè) Mirror 對(duì)象扁眯,通過它來查詢這個(gè)實(shí)例的屬性、方法等翅帜。

class Person {
    var age: Int = 18
    var name: String = "小明"
}

var p = Person()

// 首先通過構(gòu)造方法創(chuàng)建一個(gè)Mirror實(shí)例,  傳入的參數(shù)是:Any, 也就意味著當(dāng)前可以是類姻檀、結(jié)構(gòu)體、枚舉等
let mirror = Mirror(reflecting: p)
// 遍歷 children 屬性
for pro in mirror.children{
    // 通過 label 輸出當(dāng)前的名稱, value 輸出當(dāng)前反射的值
    print("\(pro.label):\(pro.value)")
}

// 打印反射對(duì)象的類型
print("subjectType:\(mirror.subjectType)")

// 打印反射的類型
print("displayStyle:\(mirror.displayStyle))")

// 打印結(jié)果
Optional("age"):18
Optional("name"):小明
subjectType:Person
displayStyle:Optional(Swift.Mirror.DisplayStyle.class))

如果將 Person 換成 Stuct 那么最后 displayStyle 的打印結(jié)果是

displayStyle:Optional(Swift.Mirror.DisplayStyle.struct))

2. Mirror的實(shí)際使用案例

func test(_ mirrorObj: Any) -> Any {
    
    let mirror = Mirror(reflecting: mirrorObj)
    // 如果當(dāng)前實(shí)例對(duì)象的子屬性為空 著返回當(dāng)前實(shí)例
    guard !mirror.children.isEmpty else {
        return mirrorObj;
    }
    
    var result: [String: Any] = [:]
    // 遍歷 children 屬性
    for child in mirror.children{
        if let key = child.label {
            // 遞歸調(diào)用test方法, 直到當(dāng)前的屬性已經(jīng)沒有子屬性了
            result[key] = test(child.value)
        } else {
            print("no key")
        }
    }
    return result
}

class Person {
    var age: Int = 18
    var name: String = "小明"
}

var p = Person()
var result = test(p)
print(result)


// 打印結(jié)果
["age": 18, "name": "小明"]

這個(gè)例子只是簡(jiǎn)單的一個(gè)將實(shí)例對(duì)象的屬性轉(zhuǎn)換成字典涝滴。接下來編寫一個(gè)功能完善的簡(jiǎn)易的模型轉(zhuǎn)字典案例

// 定義一個(gè)協(xié)議
protocol LJLJsonMap {
    // 聲明一個(gè)模型轉(zhuǎn)字典的方法
    func jsonMap() throws -> Any
}

// 定義一個(gè) 錯(cuò)誤枚舉
enum JsonMapError: Error {
    case emptyKey // 沒有屬性名稱
    case noProtocol // 沒有遵守協(xié)議
}

// 定義一個(gè)擴(kuò)展 實(shí)現(xiàn) 錯(cuò)誤具體的返回
extension JsonMapError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .emptyKey:
            return "當(dāng)前實(shí)例對(duì)象沒有屬性"
        case .noProtocol:
            return "當(dāng)前實(shí)例對(duì)象的類型或?qū)傩缘念愋蜎]有遵守協(xié)議"
        }
    }
}

// 定義一個(gè)擴(kuò)展 具體實(shí)現(xiàn) jsonMap()
extension LJLJsonMap {
    func jsonMap() throws -> Any {
        let mirror = Mirror(reflecting: self)
        // 如果當(dāng)前實(shí)例對(duì)象的子屬性為空 著返回當(dāng)前實(shí)例
        guard !mirror.children.isEmpty else {
            return self;
        }
    
        var result: [String: Any] = [:]
        // 遍歷 children 屬性
        for child in mirror.children {
            if let value = child.value as? LJLJsonMap {
                if let key = child.label {
                    // 遞歸調(diào)用jsonMap方法, 直到當(dāng)前的屬性已經(jīng)沒有子屬性了
                    result[key] = try value.jsonMap()
                } else {
                    throw JsonMapError.emptyKey
                }
            } else {
                throw JsonMapError.noProtocol
            }
            
        }
        return result
    }
}

class PersonClass {
    var age: Int = 18
}

class PersonClass2 {
    var name: String = "小明"
}

struct PersonStruct {
    var weight: Double = 55.5
}

extension PersonClass: LJLJsonMap {}
extension PersonClass2: LJLJsonMap {}
extension PersonStruct: LJLJsonMap {}

// 因?yàn)?jsonMap 方法中遞歸調(diào)用 jsonMap 所以這幾個(gè)類型都需要遵守 LJLJsonMap 協(xié)議
extension Int: LJLJsonMap{}
extension Double: LJLJsonMap{}

在上述代碼的基礎(chǔ)上執(zhí)行一下代碼

var pClass = PersonClass()

do {
    let resultClass = try pClass.jsonMap()
    print(resultClass)
} catch {
    print(error.localizedDescription.description)
}

// 打印結(jié)果
["age": 18]
// 注意 Person2 中的 name 屬性為 String 并且 String 沒有遵守 LJLJsonMap 協(xié)議
var pClass = PersonClass2()

do {
    let result = try pClass.jsonMap()
    print(result)
} catch {
    print(error.localizedDescription.description)
}

// 打印結(jié)果
當(dāng)前實(shí)例對(duì)象的類型或?qū)傩缘念愋蜎]有遵守協(xié)議
var pStruct = PersonStruct()

do {
    let result = try pStruct.jsonMap()
    print(result)
} catch {
    print(error.localizedDescription.description)
}

// 打印結(jié)果
["weight": 55.5]

3. Mirror源碼窺探

首先在 Swift源碼 中找到 Mirror.Swift 文件绣版。在源碼中我們可以看到 Mirror 是由結(jié)構(gòu)體實(shí)現(xiàn)的

public struct Mirror {

找到初始化方法 init()

public init(reflecting subject: Any) {
    if case let customized as CustomReflectable = subject {
      self = customized.customMirror
    } else {
      self = Mirror(internalReflecting: subject)
    }
  }

可以發(fā)現(xiàn)這里接收的是一個(gè) Any 類型的參數(shù)胶台。在方法體里有一個(gè) if case 的判斷語句,判斷傳入的 subject 是否遵循了 CustomReflectable 協(xié)議杂抽,如果是則直接調(diào)用 customMirror
對(duì)于 CustomReflectable 的用法如下

class Person: CustomReflectable {
    var age: Int
    var name: String
    init(_ age: Int, _ name: String) {
        self.age = age
        self.name = name
    }
    
    var customMirror: Mirror {
        let info = KeyValuePairs<String, Any>.init(dictionaryLiteral: ("age", age), ("name", name))
        let mirror = Mirror.init(self, children: info, displayStyle: .class, ancestorRepresentation: .generated)
        return mirror
    }
}

實(shí)現(xiàn)這個(gè) CustomReflectable 最直觀的區(qū)別在 LLDB 調(diào)試時(shí)诈唬。

未實(shí)現(xiàn)CustomReflectable協(xié)議.png

實(shí)現(xiàn)了CustomReflectable協(xié)議.png

回到源碼中,如果沒有遵循 CustomReflectable 協(xié)議就進(jìn)行下級(jí)的函數(shù)調(diào)用 Mirror(internalReflecting: subject)缩麸。通過這個(gè)函數(shù)可以定位到 ReflectionMirror.swift 文件中的 init(internalReflecting subject: Any, subjectType: Any.Type? = nil, customAncestor: Mirror? = nil) 方法

internal init(internalReflecting subject: Any,
              subjectType: Any.Type? = nil,
              customAncestor: Mirror? = nil)
  {
    let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
    
    let childCount = _getChildCount(subject, type: subjectType)
    let children = (0 ..< childCount).lazy.map({
      getChild(of: subject, type: subjectType, index: $0)
    })
    self.children = Children(children)
    
    self._makeSuperclassMirror = {
      guard let subjectClass = subjectType as? AnyClass,
            let superclass = _getSuperclass(subjectClass) else {
        return nil
      }
      
      // Handle custom ancestors. If we've hit the custom ancestor's subject type,
      // or descendants are suppressed, return it. Otherwise continue reflecting.
      if let customAncestor = customAncestor {
        if superclass == customAncestor.subjectType {
          return customAncestor
        }
        if customAncestor._defaultDescendantRepresentation == .suppressed {
          return customAncestor
        }
      }
      return Mirror(internalReflecting: subject,
                    subjectType: superclass,
                    customAncestor: customAncestor)
    }
    
    let rawDisplayStyle = _getDisplayStyle(subject)
    switch UnicodeScalar(Int(rawDisplayStyle)) {
    case "c": self.displayStyle = .class
    case "e": self.displayStyle = .enum
    case "s": self.displayStyle = .struct
    case "t": self.displayStyle = .tuple
    case "\0": self.displayStyle = nil
    default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
    }
    
    self.subjectType = subjectType
    self._defaultDescendantRepresentation = .generated
  }

首先第一步

let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))

這里是獲取 subject 的類型铸磅,前面調(diào)用這個(gè)函數(shù)的時(shí)候沒有傳入 subjectType 所以 subject 的類型是通過后面的 _getNormalizedType(subject, type: type(of: subject)) 的函數(shù)去獲取的。

@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type

定位到 _getNormalizedType() 函數(shù)可以發(fā)現(xiàn)這里其實(shí)是調(diào)用的 C++ 的方法 swift_reflectionMirror_normalizedType杭朱。前面的 @_silgen_name 是編譯器字段阅仔,是 Swift 一個(gè)隱藏的符號(hào),作用是將 C/C++ 的函數(shù)直接映射為 Swift 函數(shù)弧械。

// func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
                                                      const Metadata *type,
                                                      const Metadata *T) {
  return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}

找到 swift_reflectionMirror_normalizedType 函數(shù)是在 ReflectionMirror.cpp 文件中八酒,發(fā)現(xiàn)這里返回的是 call 函數(shù)的調(diào)用,那么定位到 call 函數(shù)的實(shí)現(xiàn)梦谜,

 auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
          const F &f) -> decltype(f(nullptr))
{
  const Metadata *type;
  OpaqueValue *value;
  std::tie(type, value) = unwrapExistential(T, passedValue);
  
  if (passedType != nullptr) {
    type = passedType;
  }
  
  auto call = [&](ReflectionMirrorImpl *impl) {
    impl->type = type;
    impl->value = value;
    auto result = f(impl);
    return result;
  };
  ...
}

發(fā)現(xiàn)這就是一個(gè)回調(diào)函數(shù)丘跌,回調(diào)的具體數(shù)據(jù)都是由 ReflectionMirrorImpl 結(jié)構(gòu)體來實(shí)現(xiàn)的。定位到 ReflectionMirrorImpl 結(jié)構(gòu)體

// Abstract base class for reflection implementations.
struct ReflectionMirrorImpl {
  const Metadata *type;
  OpaqueValue *value;
  
  virtual char displayStyle() = 0;
  virtual intptr_t count() = 0;
  virtual intptr_t childOffset(intptr_t index) = 0;
  virtual const FieldType childMetadata(intptr_t index,
                                        const char **outName,
                                        void (**outFreeFunc)(const char *)) = 0;
  virtual AnyReturn subscript(intptr_t index, const char **outName,
                              void (**outFreeFunc)(const char *)) = 0;
  virtual const char *enumCaseName() { return nullptr; }

#if SWIFT_OBJC_INTEROP
  virtual id quickLookObject() { return nil; }
#endif
  
  // For class types, traverse through superclasses when providing field
  // information. The base implementations call through to their local-only
  // counterparts.
  virtual intptr_t recursiveCount() {
    return count();
  }
  virtual intptr_t recursiveChildOffset(intptr_t index) {
    return childOffset(index);
  }
  virtual const FieldType recursiveChildMetadata(intptr_t index,
                                                 const char **outName,
                                                 void (**outFreeFunc)(const char *))
  {
    return childMetadata(index, outName, outFreeFunc);
  }

  virtual ~ReflectionMirrorImpl() {}
};

可以發(fā)現(xiàn) ReflectionMirrorImpl 是一個(gè)抽象類唁桩,也就意味著不同類型的反射都需要實(shí)現(xiàn) ReflectionMirrorImpl 并且在 ReflectionMirror.cpp 文件的下方可以看到 TupleStruct 耸棒、 Enum 荒澡、 Class 的具體實(shí)現(xiàn)。
StructImpl 的實(shí)現(xiàn)

// Implementation for structs.
struct StructImpl : ReflectionMirrorImpl {
  bool isReflectable() {
    const auto *Struct = static_cast<const StructMetadata *>(type);
    const auto &Description = Struct->getDescription();
    return Description->isReflectable();
  }

  char displayStyle() override {
    return 's';
  }
  
  intptr_t count() override {
    if (!isReflectable()) {
      return 0;
    }

    auto *Struct = static_cast<const StructMetadata *>(type);
    return Struct->getDescription()->NumFields;
  }

  intptr_t childOffset(intptr_t i) override {
    auto *Struct = static_cast<const StructMetadata *>(type);

    if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
      swift::crash("Swift mirror subscript bounds check failure");

    // Load the offset from its respective vector.
    return Struct->getFieldOffsets()[i];
  }

  const FieldType childMetadata(intptr_t i, const char **outName,
                                void (**outFreeFunc)(const char *)) override {
    StringRef name;
    FieldType fieldInfo;
    std::tie(name, fieldInfo) = getFieldAt(type, i);
    assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
    
    *outName = name.data();
    *outFreeFunc = nullptr;
    
    return fieldInfo;
  }

  AnyReturn subscript(intptr_t i, const char **outName,
                      void (**outFreeFunc)(const char *)) override {
    auto fieldInfo = childMetadata(i, outName, outFreeFunc);

    auto *bytes = reinterpret_cast<char*>(value);
    auto fieldOffset = childOffset(i);
    auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);

    return copyFieldContents(fieldData, fieldInfo);
  }
};
  bool isReflectable() {
    const auto *Struct = static_cast<const StructMetadata *>(type);
    const auto &Description = Struct->getDescription();
    return Description->isReflectable();
  }

獲取是否可以反射与殃,可以看到這里面首先將 StructMetadata 進(jìn)行強(qiáng)制轉(zhuǎn)換单山,然后獲取到 Matadata 中的 Description 再獲取到 Description 中的 isRelectable 字段。

  intptr_t count() override {
    if (!isReflectable()) {
      return 0;
    }

    auto *Struct = static_cast<const StructMetadata *>(type);
    return Struct->getDescription()->NumFields;
  }

獲取屬性的數(shù)量幅疼,可以看到首先判斷是否可以反射米奸,不可以就返回 0 ,可以就還是將 StructMetadata 進(jìn)行強(qiáng)制轉(zhuǎn)換窥浪,然后獲取到 Description 中的 NumFields

  AnyReturn subscript(intptr_t i, const char **outName,
                      void (**outFreeFunc)(const char *)) override {
    auto fieldInfo = childMetadata(i, outName, outFreeFunc);

    auto *bytes = reinterpret_cast<char*>(value);
    auto fieldOffset = childOffset(i);
    auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);

    return copyFieldContents(fieldData, fieldInfo);
  }

可以看到 fieldInfo 是通過 childMetadata() 獲取

 const FieldType childMetadata(intptr_t i, const char **outName,
                                void (**outFreeFunc)(const char *)) override {
    StringRef name;
    FieldType fieldInfo;
    std::tie(name, fieldInfo) = getFieldAt(type, i);
    assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
    
    *outName = name.data();
    *outFreeFunc = nullptr;
    
    return fieldInfo;
  }

可以看到 std::tie(name, fieldInfo) = getFieldAt(type, i); 這句代碼中調(diào)用了 getFieldAt

 getFieldAt(const Metadata *base, unsigned index) {
  ...
  auto *baseDesc = base->getTypeContextDescriptor();
  if (!baseDesc)
    return failedToFindMetadata();

  auto *fields = baseDesc->Fields.get();
  ...
}

主要看這里掺逼,獲取描述文件 Descriptor 娇澎,然后獲取 Fieilds ,在獲取到 Fieilds 中的屬性的信息铡溪。在前面的文章 Swift探索(一): 類與結(jié)構(gòu)體(上)Swift探索(二): 類與結(jié)構(gòu)體(下) 當(dāng)中我們提到過 StructClass 泪喊、 Enum 都有自己的 Metadata 棕硫, 并且 Metadata 中都有與之對(duì)應(yīng)的 TypeDescriptor
通過對(duì) TupleImpl 袒啼、 EnumImpl 哈扮、 ClassImpl 的分析實(shí)現(xiàn)方式基本與 StructImpl 相同纬纪,都是通過 Matadata 類型的元數(shù)據(jù)、 getDescription 類型的描述 滑肉、 FieldDescrition 類型的屬性的描述去實(shí)現(xiàn)育八。

4. 利用Mirror源碼的原理實(shí)現(xiàn)解析小工具

首先通過源碼分別獲取到 EnumStruct 赦邻、 Class 這三種類型中的 Metadata髓棋。

4.1 Enum 的實(shí)現(xiàn)
4.1.1 還原TargetEnumMetadata

首先定位到源碼中的 Metadata.h 文件中,找到 TargetEnumMetadata 代碼如下

struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
// 全是方法
...
}

我們發(fā)現(xiàn)這里面全是方法惶洲,并且 TargetEnumMetadata 繼承自 TargetValueMetadata 按声,那么進(jìn)入到 TargetValueMetadata

struct TargetValueMetadata : public TargetMetadata<Runtime> {
  ...
  /// An out-of-line description of the type.
  TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
  ...
};

發(fā)現(xiàn)有一個(gè)屬性 Description 并且 TargetValueMetadata 繼承自 TargetMetadata ,進(jìn)入到 TargetMetadata

struct TargetMetadata {
...
private:
  /// The kind. Only valid for non-class metadata; getKind() must be used to get
  /// the kind value.
  StoredPointer Kind;
...
};

發(fā)現(xiàn)有一個(gè)屬性 Kind 由此可以推測(cè)出 TargetEnumMetadata 的結(jié)構(gòu)為

struct TargetEnumMetadata {
    var kind: Int
    var typeDescriptor: UnsafeMutablePointer<Any>
}
4.1.2 還原typeDescriptor

其中 typeDescriptor 就是枚舉 metadata 的描述信息恬吕,回到源碼的 TargetEnumMetadata

struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  using StoredSize = typename Runtime::StoredSize;
  using TargetValueMetadata<Runtime>::TargetValueMetadata;

  const TargetEnumDescriptor<Runtime> *getDescription() const {
    return llvm::cast<TargetEnumDescriptor<Runtime>>(this->Description);
  }
...
};

可以看到這里進(jìn)行了一個(gè)類型轉(zhuǎn)換签则,轉(zhuǎn)換成了 TargetEnumDescriptor ,定位到 TargetEnumDescriptor

class TargetEnumDescriptor final
    : public TargetValueTypeDescriptor<Runtime>,
      public TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
                            TargetTypeGenericContextDescriptorHeader,
                            /*additional trailing objects*/
                            TargetForeignMetadataInitialization<Runtime>,
                            TargetSingletonMetadataInitialization<Runtime>,
                            TargetCanonicalSpecializedMetadatasListCount<Runtime>,
                            TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
                            TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
  ...
  /// The number of non-empty cases in the enum are in the low 24 bits;
  /// the offset of the payload size in the metadata record in words,
  /// if any, is stored in the high 8 bits.
  uint32_t NumPayloadCasesAndPayloadSizeOffset;

  /// The number of empty cases in the enum.
  uint32_t NumEmptyCases;
  ...
};

發(fā)現(xiàn) TargetEnumDescriptor 中有兩個(gè)屬性 uint32_t NumPayloadCasesAndPayloadSizeOffsetuint32_t NumEmptyCases 并且繼承自 TargetValueTypeDescriptor 铐料,定位到 TargetValueTypeDescriptor

class TargetValueTypeDescriptor
    : public TargetTypeContextDescriptor<Runtime> {
public:
  static bool classof(const TargetContextDescriptor<Runtime> *cd) {
    return cd->getKind() == ContextDescriptorKind::Struct ||
           cd->getKind() == ContextDescriptorKind::Enum;
  }
};

沒有屬性渐裂,繼承自 TargetTypeContextDescriptor , 定位到 TargetTypeContextDescriptor

class TargetTypeContextDescriptor
    : public TargetContextDescriptor<Runtime> {
public:
  /// The name of the type.
  TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;

  /// A pointer to the metadata access function for this type.
  ///
  /// The function type here is a stand-in. You should use getAccessFunction()
  /// to wrap the function pointer in an accessor that uses the proper calling
  /// convention for a given number of arguments.
  TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
                              /*Nullable*/ true> AccessFunctionPtr;
  
  /// A pointer to the field descriptor for the type, if any.
  TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
                              /*nullable*/ true> Fields;
      
  ...
};

發(fā)現(xiàn)有三個(gè) TargetRelativeDirectPointer 類型的的屬性 Name 钠惩、 AccessFunctionPtr 柒凉、 Fields ,并且 TargetTypeContextDescriptor 繼承自 TargetContextDescriptor 篓跛,定位到 TargetContextDescriptor

struct TargetContextDescriptor {
  /// Flags describing the context, including its kind and format version.
  ContextDescriptorFlags Flags;
  
  /// The parent context, or null if this is a top-level context.
  TargetRelativeContextPointer<Runtime> Parent;

  ...
};

發(fā)現(xiàn) TargetContextDescriptor 是個(gè)基類膝捞,并且有兩個(gè)屬性 ContextDescriptorFlags 類型的 Flags ,和 TargetRelativeContextPointer 類型的 Parent 愧沟, 定位到 ContextDescriptorFlags

struct ContextDescriptorFlags {
private:
  uint32_t Value;

  explicit constexpr ContextDescriptorFlags(uint32_t Value)
    : Value(Value) {}
public:
  constexpr ContextDescriptorFlags() : Value(0) {}
  constexpr ContextDescriptorFlags(ContextDescriptorKind kind,
                                   bool isGeneric,
                                   bool isUnique,
                                   uint8_t version,
                                   uint16_t kindSpecificFlags)
    : ContextDescriptorFlags(ContextDescriptorFlags()
                               .withKind(kind)
                               .withGeneric(isGeneric)
                               .withUnique(isUnique)
                               .withVersion(version)
                               .withKindSpecificFlags(kindSpecificFlags))
  {}
  ...
};

發(fā)現(xiàn) Flags 其實(shí)就是 uint32_t 類型蔬咬,按位存儲(chǔ)著 kindisGeneric 沐寺、 isUnique 林艘、 versionkindSpecificFlags等信息混坞。因此最終可以得出 TargetEnumDescriptor 具體的數(shù)據(jù)結(jié)構(gòu)如下

struct TargetEnumDescriptor {
    var flags: UInt32
    var parent: TargetRelativeContextPointer<UnsafeRawPointer>
    var name: TargetRelativeDirectPointer<CChar>
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<UnsafeRawPointer>
    var numPayloadCasesAndPayloadSizeOffset: UInt32
    var numEmptyCases: UInt32
}

接下來分析 TargetRelativeContextPointerTargetRelativeDirectPointer 具體是什么

4.1.3 TargetRelativeContextPointer

定位到 TargetRelativeContextPointer

template<typename Runtime,
         template<typename _Runtime> class Context = TargetContextDescriptor>
using TargetRelativeContextPointer =
  RelativeIndirectablePointer<const Context<Runtime>,
                              /*nullable*/ true, int32_t,
                              TargetSignedContextPointer<Runtime, Context>>;

可以看到這是一個(gè)別名的定義給 RelativeIndirectablePointer 取了一個(gè)別名 TargetRelativeContextPointer 狐援, 定位到 RelativeIndirectablePointer

/// A relative reference to an object stored in memory. The reference may be
/// direct or indirect, and uses the low bit of the (assumed at least
/// 2-byte-aligned) pointer to differentiate.
template<typename ValueTy, bool Nullable = false, typename Offset = int32_t, typename IndirectType = const ValueTy *>
class RelativeIndirectablePointer {
private:
  static_assert(std::is_integral<Offset>::value &&
                std::is_signed<Offset>::value,
                "offset type should be signed integer");
  
  /// The relative offset of the pointer's memory from the `this` pointer.
  /// If the low bit is clear, this is a direct reference; otherwise, it is
  /// an indirect reference.
  Offset RelativeOffsetPlusIndirect;

  /// RelativePointers should appear in statically-generated metadata. They
  /// shouldn't be constructed or copied.
  RelativeIndirectablePointer() = delete;
  RelativeIndirectablePointer(RelativeIndirectablePointer &&) = delete;
  RelativeIndirectablePointer(const RelativeIndirectablePointer &) = delete;
  RelativeIndirectablePointer &operator=(RelativeIndirectablePointer &&)
    = delete;
  RelativeIndirectablePointer &operator=(const RelativeIndirectablePointer &)
    = delete;

public:
  /// Allow construction and reassignment from an absolute pointer.
  /// These always produce a direct relative offset.
  RelativeIndirectablePointer(ValueTy *absolute)
  : RelativeOffsetPlusIndirect(
      Nullable && absolute == nullptr
        ? 0
        : detail::measureRelativeOffset<Offset>(absolute, this)) {
    if (!Nullable)
      assert(absolute != nullptr &&
             "constructing non-nullable relative pointer from null");
  }
  
  RelativeIndirectablePointer &operator=(ValueTy *absolute) & {
    if (!Nullable)
      assert(absolute != nullptr &&
             "constructing non-nullable relative pointer from null");
      
    RelativeOffsetPlusIndirect = Nullable && absolute == nullptr
      ? 0
      : detail::measureRelativeOffset<Offset>(absolute, this);
    return *this;
  }

  const ValueTy *get() const & {
    static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
                  "alignment of value and offset must be at least 2 to "
                  "make room for indirectable flag");
  
    // Check for null.
    if (Nullable && RelativeOffsetPlusIndirect == 0)
      return nullptr;
    
    Offset offsetPlusIndirect = RelativeOffsetPlusIndirect;
    uintptr_t address = detail::applyRelativeOffset(this,
                                                    offsetPlusIndirect & ~1);

    // If the low bit is set, then this is an indirect address. Otherwise,
    // it's direct.
    if (offsetPlusIndirect & 1) {
      return *reinterpret_cast<IndirectType const *>(address);
    } else {
      return reinterpret_cast<const ValueTy *>(address);
    }
  }

  /// A zero relative offset encodes a null reference.
  bool isNull() const & {
    return RelativeOffsetPlusIndirect == 0;
  }
  
  operator const ValueTy* () const & {
    return get();
  }

  const ValueTy *operator->() const & {
    return get();
  }
};

這個(gè)類主要作用是存儲(chǔ)在內(nèi)存中的對(duì)象的相對(duì)引用(相對(duì)引用指的是當(dāng)前引用的內(nèi)存地址,到當(dāng)前對(duì)象的內(nèi)存地址的距離)拔第。通過 RelativeOffsetPlusIndirect 屬性存儲(chǔ)相對(duì)的地址偏移量咕村,再通過 get() 方法獲取。

const ValueTy *get() const & {
    static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
                  "alignment of value and offset must be at least 2 to "
                  "make room for indirectable flag");
  
    // Check for null.
    if (Nullable && RelativeOffsetPlusIndirect == 0)
      return nullptr;
    
    Offset offsetPlusIndirect = RelativeOffsetPlusIndirect;
    uintptr_t address = detail::applyRelativeOffset(this,
                                                    offsetPlusIndirect & ~1);

    // If the low bit is set, then this is an indirect address. Otherwise,
    // it's direct.
    if (offsetPlusIndirect & 1) {
      return *reinterpret_cast<IndirectType const *>(address);
    } else {
      return reinterpret_cast<const ValueTy *>(address);
    }
  }

get() 函數(shù)中蚊俺,會(huì)調(diào)用 applyRelativeOffset 函數(shù)懈涛,進(jìn)行地址的偏移

static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
  static_assert(std::is_integral<Offset>::value &&
                std::is_signed<Offset>::value,
                "offset type should be signed integer");

  auto base = reinterpret_cast<uintptr_t>(basePtr);
  // We want to do wrapping arithmetic, but with a sign-extended
  // offset. To do this in C, we need to do signed promotion to get
  // the sign extension, but we need to perform arithmetic on unsigned values,
  // since signed overflow is undefined behavior.
  auto extendOffset = (uintptr_t)(intptr_t)offset;
  return base + extendOffset;
}

applyRelativeOffset 中的返回可以發(fā)現(xiàn)返回的是 base + extendOffset 基地址加上偏移的值。因此 TargetRelativeContextPointer 可以通過 Swift 代碼還原

// 傳入指針
struct TargetRelativeContextPointer <Pointee>{
    var offset: Int32
    
    mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
        
        let offset = self.offset
        
        return withUnsafePointer(to: &self) { p in
            // 獲取指針地址 偏移offset后 重新綁定為傳入的指針的類型
            let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
            return UnsafeMutablePointer(mutating: pointer)
        }
    }
}
4.1.4 還原TargetRelativeDirectPointer

定位到 TargetRelativeDirectPointer

template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeDirectPointer
  = typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;

可以發(fā)現(xiàn)這里跟 TargetRelativeContextPointer 一樣也是給 RelativeDirectPointer 取了一個(gè)別名 TargetRelativeDirectPointer 泳猬, 定位到 RelativeDirectPointer

/// A direct relative reference to an object that is not a function pointer.
template <typename T, bool Nullable, typename Offset>
class RelativeDirectPointer<T, Nullable, Offset,
    typename std::enable_if<!std::is_function<T>::value>::type>
    : private RelativeDirectPointerImpl<T, Nullable, Offset>
{
  using super = RelativeDirectPointerImpl<T, Nullable, Offset>;
public:
  using super::get;
  using super::super;
  
  RelativeDirectPointer &operator=(T *absolute) & {
    super::operator=(absolute);
    return *this;
  }

  operator typename super::PointerTy() const & {
    return this->get();
  }

  const typename super::ValueTy *operator->() const & {
    return this->get();
  }

  using super::isNull;
};

發(fā)現(xiàn)這里調(diào)用的其實(shí)是 RelativeDirectPointerImpl 中的函數(shù)批钠, 定位到 RelativeDirectPointerImpl

/// A relative reference to a function, intended to reference private metadata
/// functions for the current executable or dynamic library image from
/// position-independent constant data.
template<typename T, bool Nullable, typename Offset>
class RelativeDirectPointerImpl {
private:
  /// The relative offset of the function's entry point from *this.
  Offset RelativeOffset;

  /// RelativePointers should appear in statically-generated metadata. They
  /// shouldn't be constructed or copied.
  RelativeDirectPointerImpl() = delete;
  /// RelativePointers should appear in statically-generated metadata. They
  /// shouldn't be constructed or copied.
  RelativeDirectPointerImpl(RelativeDirectPointerImpl &&) = delete;
  RelativeDirectPointerImpl(const RelativeDirectPointerImpl &) = delete;
  RelativeDirectPointerImpl &operator=(RelativeDirectPointerImpl &&)
    = delete;
  RelativeDirectPointerImpl &operator=(const RelativeDirectPointerImpl &)
    = delete;


public:
  using ValueTy = T;
  using PointerTy = T*;

  // Allow construction and reassignment from an absolute pointer.
  RelativeDirectPointerImpl(PointerTy absolute)
    : RelativeOffset(Nullable && absolute == nullptr
                       ? 0
                       : detail::measureRelativeOffset<Offset>(absolute, this))
  {
    if (!Nullable)
      assert(absolute != nullptr &&
             "constructing non-nullable relative pointer from null");
  }
  explicit constexpr RelativeDirectPointerImpl(std::nullptr_t)
  : RelativeOffset (0) {
    static_assert(Nullable, "can't construct non-nullable pointer from null");
  }
  
  RelativeDirectPointerImpl &operator=(PointerTy absolute) & {
    if (!Nullable)
      assert(absolute != nullptr &&
             "constructing non-nullable relative pointer from null");
    RelativeOffset = Nullable && absolute == nullptr
      ? 0
      : detail::measureRelativeOffset<Offset>(absolute, this);
    return *this;
  }

  PointerTy get() const & {
    // Check for null.
    if (Nullable && RelativeOffset == 0)
      return nullptr;
    
    // The value is addressed relative to `this`.
    uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
    return reinterpret_cast<PointerTy>(absolute);
  }

  /// A zero relative offset encodes a null reference.
  bool isNull() const & {
    return RelativeOffset == 0;
  }
};

發(fā)現(xiàn)這里跟 TargetRelativeContextPointer 基本一樣宇植,都是存儲(chǔ)在內(nèi)存中的對(duì)象的相對(duì)引用,于是優(yōu)化一下已經(jīng)還原的 EnumMetadata 的結(jié)構(gòu)體如下

// 傳入指針
struct TargetRelativeDirectPointer<Pointee>{
    var offset: Int32
    
    mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
        
        let offset = self.offset
        
        return withUnsafePointer(to: &self) { p in
            // 獲取指針地址 偏移offset后 重新綁定為傳入的指針的類型
            let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
            return UnsafeMutablePointer(mutating: pointer)
        }
    }
}

struct TargetEnumMetadata {
    var kind: Int
    var typeDescriptor: UnsafeMutablePointer<TargetEnumDescriptor>
}

struct TargetEnumDescriptor {
    var flags: UInt32
    var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
    var name: TargetRelativeDirectPointer<CChar>
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<UnsafeRawPointer>
    var numPayloadCasesAndPayloadSizeOffset: UInt32
    var numEmptyCases: UInt32
}
4.1.5 還原fieldDescriptor

在源碼中

class TargetTypeContextDescriptor
    : public TargetContextDescriptor<Runtime> {
public:
  ...
  /// A pointer to the field descriptor for the type, if any.
  TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
                              /*nullable*/ true> Fields;
  ...
};

注意到這里使用的命名空間中的 FieldDescriptor 埋心,進(jìn)入 FieldDescriptor

class FieldDescriptor {
  const FieldRecord *getFieldRecordBuffer() const {
    return reinterpret_cast<const FieldRecord *>(this + 1);
  }

public:
  const RelativeDirectPointer<const char> MangledTypeName;
  const RelativeDirectPointer<const char> Superclass;

  FieldDescriptor() = delete;

  const FieldDescriptorKind Kind;
  const uint16_t FieldRecordSize;
  const uint32_t NumFields;

  using const_iterator = FieldRecordIterator;

  bool isEnum() const {
    return (Kind == FieldDescriptorKind::Enum ||
            Kind == FieldDescriptorKind::MultiPayloadEnum);
  }

  bool isClass() const {
    return (Kind == FieldDescriptorKind::Class ||
            Kind == FieldDescriptorKind::ObjCClass);
  }

  bool isProtocol() const {
    return (Kind == FieldDescriptorKind::Protocol ||
            Kind == FieldDescriptorKind::ClassProtocol ||
            Kind == FieldDescriptorKind::ObjCProtocol);
  }

  bool isStruct() const {
    return Kind == FieldDescriptorKind::Struct;
  }

  const_iterator begin() const {
    auto Begin = getFieldRecordBuffer();
    auto End = Begin + NumFields;
    return const_iterator { Begin, End };
  }

  const_iterator end() const {
    auto Begin = getFieldRecordBuffer();
    auto End = Begin + NumFields;
    return const_iterator { End, End };
  }

  llvm::ArrayRef<FieldRecord> getFields() const {
    return {getFieldRecordBuffer(), NumFields};
  }

  bool hasMangledTypeName() const {
    return MangledTypeName;
  }

  StringRef getMangledTypeName() const {
    return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get());
  }

  bool hasSuperclass() const {
    return Superclass;
  }

  StringRef getSuperclass() const {
    return Demangle::makeSymbolicMangledNameStringRef(Superclass.get());
  }
};

可以發(fā)現(xiàn)有 RelativeDirectPointer 類型的屬性 MangledTypeNameSuperclass 指郁、FieldDescriptorKind 類型的屬性 Kinduint16_t 類型的屬性 FieldRecordSize 拷呆、 uint32_t 類型的屬性 NumFields闲坎, 并且發(fā)現(xiàn)第一行代碼中調(diào)用了一個(gè)方法通過 this+1 的方式一個(gè)一個(gè)的訪問屬性,所以這是一塊連續(xù)的內(nèi)存空間茬斧。進(jìn)入 FieldRecord

class FieldRecord {
  const FieldRecordFlags Flags;

public:
  const RelativeDirectPointer<const char> MangledTypeName;
  const RelativeDirectPointer<const char> FieldName;

  FieldRecord() = delete;

  bool hasMangledTypeName() const {
    return MangledTypeName;
  }

  StringRef getMangledTypeName() const {
    return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get());
  }

  StringRef getFieldName() const {
    return FieldName.get();
  }

  bool isIndirectCase() const {
    return Flags.isIndirectCase();
  }

  bool isVar() const {
    return Flags.isVar();
  }
};

發(fā)現(xiàn) FieldRecord 有三個(gè)屬性 FieldRecordFlags 類型的 Flags 也就是 uint32_t類型腰懂、 RelativeDirectPointer 類型的 MangledTypeNameFieldName 。因此能夠得到 fieldDescriptor 的結(jié)構(gòu)體如下

struct FieldDescriptor {
    var mangledTypeName: TargetRelativeDirectPointer<CChar>
    var superclass: TargetRelativeDirectPointer<CChar>
    var kind: UInt16
    var fieldRecordSize: Int16
    var numFields: Int32
    var fields: FiledRecordBuffer<FieldRecord>
}

struct FieldRecord {
    var fieldRecordFlags: Int32
    var mangledTypeName: TargetRelativeDirectPointer<CChar>
    var fieldName: TargetRelativeDirectPointer<UInt8>
}

struct FiledRecordBuffer<Element>{
    var element: Element
    
    mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
        return withUnsafePointer(to: &self) {
            let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
                return start
            }
            return UnsafeBufferPointer(start: ptr, count: n)
        }
    }
    
    mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
        return withUnsafePointer(to: &self) {
            return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
        }
    }
}
4.1.6 TargetEnumMetadata 最終數(shù)據(jù)結(jié)構(gòu)

通過以上分析最終得到的 TargetEnumMetadata 數(shù)據(jù)結(jié)構(gòu)如下

// 傳入指針
struct TargetRelativeDirectPointer<Pointee>{
    var offset: Int32
    
    mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
        
        let offset = self.offset
        
        return withUnsafePointer(to: &self) { p in
            // 獲取指針地址 偏移offset后 重新綁定為傳入的指針的類型
            let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
            return UnsafeMutablePointer(mutating: pointer)
        }
    }
}

struct TargetEnumMetadata {
    var kind: Int
    var typeDescriptor: UnsafeMutablePointer<TargetEnumDescriptor>
}

struct TargetEnumDescriptor {
    var flags: UInt32
    var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
    var name: TargetRelativeDirectPointer<CChar>
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
    var numPayloadCasesAndPayloadSizeOffset: UInt32
    var numEmptyCases: UInt32
}

struct FieldDescriptor {
    var mangledTypeName: TargetRelativeDirectPointer<CChar>
    var superclass: TargetRelativeDirectPointer<CChar>
    var kind: UInt16
    var fieldRecordSize: Int16
    var numFields: Int32
    var fields: FiledRecordBuffer<FieldRecord>
}

struct FieldRecord {
    var fieldRecordFlags: UInt32
    var mangledTypeName: TargetRelativeDirectPointer<CChar>
    var fieldName: TargetRelativeDirectPointer<UInt8>
}

struct FiledRecordBuffer<Element>{
    var element: Element
    
    mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
        return withUnsafePointer(to: &self) {
            let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
                return start
            }
            return UnsafeBufferPointer(start: ptr, count: n)
        }
    }
    
    mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
        return withUnsafePointer(to: &self) {
            return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
        }
    }
}
4.1.7 解析Enum的數(shù)據(jù)
enum Week {
    case Mon
    case Tue
    case Wed
    case Thu
    case Fri
    case Sat
    case Sun
}

// 按位轉(zhuǎn)換內(nèi)存指針
let ptr = unsafeBitCast(Week.self as Any.Type, to: UnsafeMutablePointer<TargetEnumMetadata>.self)

let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()

// 打印枚舉的名稱
print(String(cString: namePtr))

let field = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset()

for i in 0..<field.pointee.numFields {
    let fieldRecord = field.pointee.fields.index(of: Int(i))
    let fieldName = fieldRecord.pointee.fieldName.getApplyRelativeOffset()
    // 打印枚舉元素值的名稱
    print(String(cString: fieldName))
}

打印結(jié)果


Enum的數(shù)據(jù)打印結(jié)果.png
4.2 Class 的實(shí)現(xiàn)
4.2.1 還原TargetClassMetadata

首先定位到源碼中的 Metadata.h 文件中项秉,找到 TargetClassMetadata 代碼如下

struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
  ...
  /// Swift-specific class flags.
  ClassFlags Flags;

  /// The address point of instances of this type.
  uint32_t InstanceAddressPoint;

  /// The required size of instances of this type.
  /// 'InstanceAddressPoint' bytes go before the address point;
  /// 'InstanceSize - InstanceAddressPoint' bytes go after it.
  uint32_t InstanceSize;

  /// The alignment mask of the address point of instances of this type.
  uint16_t InstanceAlignMask;

  /// Reserved for runtime use.
  uint16_t Reserved;

  /// The total size of the class object, including prefix and suffix
  /// extents.
  uint32_t ClassSize;

  /// The offset of the address point within the class object.
  uint32_t ClassAddressPoint;

  // Description is by far the most likely field for a client to try
  // to access directly, so we force access to go through accessors.
private:
  /// An out-of-line Swift-specific description of the type, or null
  /// if this is an artificial subclass.  We currently provide no
  /// supported mechanism for making a non-artificial subclass
  /// dynamically.
  TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;

public:
  /// A function for destroying instance variables, used to clean up after an
  /// early return from a constructor. If null, no clean up will be performed
  /// and all ivars must be trivial.
  TargetSignedPointer<Runtime, ClassIVarDestroyer * __ptrauth_swift_heap_object_destructor> IVarDestroyer;
   ...
};

可以看到有 TargetClassMetadata 繼承自 TargetAnyClassMetadata 并且有 ClassFlags 類型的 Flags 屬性和 uint32_tInstanceAddressPoint 绣溜、 InstanceSizeClassSize 娄蔼、 ClassAddressPoint 屬性和 uint16_t 的 怖喻、 InstanceAlignMaskReserved 屬性和 Description 岁诉、 IVarDestroyer 屬性锚沸。進(jìn)入到 TargetAnyClassMetadata

struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
 ...

  // Note that ObjC classes do not have a metadata header.

  /// The metadata for the superclass.  This is null for the root class.
  TargetSignedPointer<Runtime, const TargetClassMetadata<Runtime> *
                                   __ptrauth_swift_objc_superclass>
      Superclass;

#if SWIFT_OBJC_INTEROP
  /// The cache data is used for certain dynamic lookups; it is owned
  /// by the runtime and generally needs to interoperate with
  /// Objective-C's use.
  TargetPointer<Runtime, void> CacheData[2];

  /// The data pointer is used for out-of-line metadata and is
  /// generally opaque, except that the compiler sets the low bit in
  /// order to indicate that this is a Swift metatype and therefore
  /// that the type metadata header is present.
  StoredSize Data;
  ...
};

發(fā)現(xiàn) TargetAnyClassMetadata 繼承自 TargetHeapMetadata 并且有三個(gè)屬性 SuperclassCacheData 唉侄、 Data 咒吐。跳轉(zhuǎn)到 TargetHeapMetadata

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
};

沒有屬性并且繼承自 TargetMetadata 跳轉(zhuǎn)至 TargetMetadata

struct TargetMetadata {
  ...
  /// The kind. Only valid for non-class metadata; getKind() must be used to get
  /// the kind value.
  StoredPointer Kind;
  ...
};

有一個(gè)屬性 Kind, 根據(jù)以上源碼分析可以得出 TargetClassMetadata 的數(shù)據(jù)結(jié)構(gòu)

struct TargetClassMetadata{
    var kind: Int
    var superClass: Any.Type
    var cacheData: (Int, Int)
    var data: Int
    var classFlags: Int32
    var instanceAddressPoint: UInt32
    var instanceSize: UInt32
    var instanceAlignmentMask: UInt16
    var reserved: UInt16
    var classSize: UInt32
    var classAddressPoint: UInt32
    var typeDescriptor: UnsafeMutablePointer<Any>
    var iVarDestroyer: UnsafeRawPointer
}
4.2.2 還原typeDescriptor

其中的 typeDescriptor 就是 class的描述信息属划,回到源碼中的 TargetClassMetadata

struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
  ...
  /// An out-of-line Swift-specific description of the type, or null
  /// if this is an artificial subclass.  We currently provide no
  /// supported mechanism for making a non-artificial subclass
  /// dynamically.
  TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
...
};

定位到 TargetClassDescriptor

class TargetClassDescriptor final
    : public TargetTypeContextDescriptor<Runtime>,
      public TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
                              TargetTypeGenericContextDescriptorHeader,
                              /*additional trailing objects:*/
                              TargetResilientSuperclass<Runtime>,
                              TargetForeignMetadataInitialization<Runtime>,
                              TargetSingletonMetadataInitialization<Runtime>,
                              TargetVTableDescriptorHeader<Runtime>,
                              TargetMethodDescriptor<Runtime>,
                              TargetOverrideTableHeader<Runtime>,
                              TargetMethodOverrideDescriptor<Runtime>,
                              TargetObjCResilientClassStubInfo<Runtime>,
                              TargetCanonicalSpecializedMetadatasListCount<Runtime>,
                              TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
                              TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
                              TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
...
  /// The type of the superclass, expressed as a mangled type name that can
  /// refer to the generic arguments of the subclass type.
  TargetRelativeDirectPointer<Runtime, const char> SuperclassType;

  union {
    /// If this descriptor does not have a resilient superclass, this is the
    /// negative size of metadata objects of this class (in words).
    uint32_t MetadataNegativeSizeInWords;

    /// If this descriptor has a resilient superclass, this is a reference
    /// to a cache holding the metadata's extents.
    TargetRelativeDirectPointer<Runtime,
                                TargetStoredClassMetadataBounds<Runtime>>
      ResilientMetadataBounds;
  };

  union {
    /// If this descriptor does not have a resilient superclass, this is the
    /// positive size of metadata objects of this class (in words).
    uint32_t MetadataPositiveSizeInWords;

    /// Otherwise, these flags are used to do things like indicating
    /// the presence of an Objective-C resilient class stub.
    ExtraClassDescriptorFlags ExtraClassFlags;
  };

  /// The number of additional members added by this class to the class
  /// metadata.  This data is opaque by default to the runtime, other than
  /// as exposed in other members; it's really just
  /// NumImmediateMembers * sizeof(void*) bytes of data.
  ///
  /// Whether those bytes are added before or after the address point
  /// depends on areImmediateMembersNegative().
  uint32_t NumImmediateMembers; // ABI: could be uint16_t?

  StoredSize getImmediateMembersSize() const {
    return StoredSize(NumImmediateMembers) * sizeof(StoredPointer);
  }

  /// Are the immediate members of the class metadata allocated at negative
  /// offsets instead of positive?
  bool areImmediateMembersNegative() const {
    return getTypeContextDescriptorFlags().class_areImmediateMembersNegative();
  }

  /// The number of stored properties in the class, not including its
  /// superclasses. If there is a field offset vector, this is its length.
  uint32_t NumFields;

private:
  /// The offset of the field offset vector for this class's stored
  /// properties in its metadata, in words. 0 means there is no field offset
  /// vector.
  ///
  /// If this class has a resilient superclass, this offset is relative to
  /// the size of the resilient superclass metadata. Otherwise, it is
  /// absolute.
  uint32_t FieldOffsetVectorOffset;
  ...
};

TargetClassDescriptor 繼承自 TargetTypeContextDescriptor 并且有 SuperclassTypeMetadataNegativeSizeInWords 候生、 MetadataPositiveSizeInWords 同眯、 NumImmediateMembersNumFields 唯鸭、 FieldOffsetVectorOffset 屬性须蜗,定位到 TargetTypeContextDescriptor

class TargetTypeContextDescriptor
    : public TargetContextDescriptor<Runtime> {
public:
  /// The name of the type.
  TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;

  /// A pointer to the metadata access function for this type.
  ///
  /// The function type here is a stand-in. You should use getAccessFunction()
  /// to wrap the function pointer in an accessor that uses the proper calling
  /// convention for a given number of arguments.
  TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
                              /*Nullable*/ true> AccessFunctionPtr;
  
  /// A pointer to the field descriptor for the type, if any.
  TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
                              /*nullable*/ true> Fields;
      
  ...
};

TargetTypeContextDescriptor 繼承自 TargetContextDescriptor 并且有 NameAccessFunctionPtr 目溉、 Fields 屬性明肮, 定位到 TargetContextDescriptor

struct TargetContextDescriptor {
  /// Flags describing the context, including its kind and format version.
  ContextDescriptorFlags Flags;
  
  /// The parent context, or null if this is a top-level context.
  TargetRelativeContextPointer<Runtime> Parent;
  ...
};

TargetContextDescriptorFlagsParent 屬性缭付。根據(jù)在上面對(duì) Enum 數(shù)據(jù)結(jié)構(gòu)的分析和 TargetClassMetadata 的源碼分析柿估,最后得出 TargetClassMetadata 的最終數(shù)據(jù)結(jié)構(gòu)為

struct TargetClassDescriptor{
    var flags: Int32
    var parent: Int32
    var name: TargetRelativeDirectPointer<CChar>
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
    var superClassType: TargetRelativeDirectPointer<CChar>
    var metadataNegativeSizeInWords: Int32
    var metadataPositiveSizeInWords: Int32
    var numImmediateMembers: Int32
    var numFields: Int32
    // 每一個(gè)屬性值距離當(dāng)前實(shí)例對(duì)象地址的偏移量
    var fieldOffsetVectorOffset: Int32
    
    func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int>{
      return metadata.assumingMemoryBound(to: Int.self).advanced(by: numericCast(self.fieldOffsetVectorOffset))
    }
    
    var genericArgumentOffset: Int {
        return 2
    }
}

struct TargetClassMetadata{
    var kind: Int
    var superClass: Any.Type
    var cacheData: (Int, Int)
    var data: Int
    var classFlags: Int32
    var instanceAddressPoint: UInt32
    var instanceSize: UInt32
    var instanceAlignmentMask: UInt16
    var reserved: UInt16
    var classSize: UInt32
    var classAddressPoint: UInt32
    var typeDescriptor: UnsafeMutablePointer<TargetClassDescriptor>
    var iVarDestroyer: UnsafeRawPointer
}
4.2.3 解析Class的數(shù)據(jù)
class Teacher {
    var age: Int = 18
    var name: String = "小明"
}

var t = Teacher()

let ptr = unsafeBitCast(Teacher.self as Any.Type, to: UnsafeMutablePointer<TargetClassMetadata>.self)

let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()
print("當(dāng)前類的名稱: \(String(cString: namePtr))")

let numFileds = ptr.pointee.typeDescriptor.pointee.numFields
print("當(dāng)前類屬性的個(gè)數(shù): \(numFileds)")

打印結(jié)果


Class的數(shù)據(jù)的打印結(jié)果.png

再獲取屬性信息

// 獲取偏移量
let offsets = ptr.pointee.typeDescriptor.pointee.getFieldOffsets(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self))

for i in 0..<numFileds{

    let fieldDespritor = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getApplyRelativeOffset()
    print("fieldDespritor: \(String(cString: fieldDespritor))")

    let fieldOffset = offsets[Int(i)]

    let typeMangleName = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getApplyRelativeOffset()

    // 獲取泛型參數(shù)
    let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)

    // 標(biāo)準(zhǔn)C語言函數(shù)庫
    let fieldType = swift_getTypeByMangledNameInContext(
        typeMangleName,
        256,
        UnsafeRawPointer(ptr.pointee.typeDescriptor),
        UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
    
    // 將fieldType轉(zhuǎn)換成Any類型
    let type = unsafeBitCast(fieldType, to: Any.Type.self)
    // 獲取首地址
    let instanceAddress = Unmanaged.passUnretained(t as AnyObject).toOpaque()
    // 將屬性的類型信息綁定到協(xié)議的類型信息
    let valueType = customCast(type: type)
    // 獲取屬性值的地址的值
    let valueValue = valueType.get(from: instanceAddress.advanced(by: fieldOffset))
    
    print("fieldType:\(type) \nfieldValue:\(valueValue) ")
}

其中 swift_getTypeByMangledNameInContext 是調(diào)用的C語言的標(biāo)準(zhǔn)函數(shù)這里通過swift橋接的形式進(jìn)行

//typeNameStart 地址信息
//typeNameLength 名稱混寫長(zhǎng)度信息
//context 上下文
//genericArgs 泛型參數(shù)
const void * _Nullable swift_getTypeByMangledNameInContext(
                        const char * _Nullable typeNameStart,
                        int typeNameLength,
                        const void * _Nullable context,
                        const void * _Nullable const * _Nullable genericArgs);

customCast(type: type) 具體內(nèi)容為

protocol BrigeProtocol {}

extension BrigeProtocol {
    // 屬性值的地址傳入進(jìn)來 后 返回屬性值
    static func get(from pointer: UnsafeRawPointer) -> Any {
        pointer.assumingMemoryBound(to: Self.self).pointee
    }
}

// 協(xié)議的metadata
struct BrigeProtocolMetadata {
    let type: Any.Type
    let witness: Int
}

func customCast(type: Any.Type) -> BrigeProtocol.Type {
    let container = BrigeProtocolMetadata(type: type, witness: 0)

    let protocolType = BrigeProtocol.Type.self
    // 按位強(qiáng)制轉(zhuǎn)換成protocolType
    let cast = unsafeBitCast(container, to: protocolType)
    return cast
}

打印結(jié)果


Class的數(shù)據(jù)的打印結(jié)果.png
4.3 Struct 的實(shí)現(xiàn)
4.3.1 還原TargetStructMetadata

首先定位到源碼中的 Metadata.h 文件中,找到 TargetStructMetadata 代碼如下

struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  using TargetValueMetadata<Runtime>::TargetValueMetadata;

  const TargetStructDescriptor<Runtime> *getDescription() const {
    return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
  }

  // The first trailing field of struct metadata is always the generic
  // argument array.

  /// Get a pointer to the field offset vector, if present, or null.
  const uint32_t *getFieldOffsets() const {
    auto offset = getDescription()->FieldOffsetVectorOffset;
    if (offset == 0)
      return nullptr;
    auto asWords = reinterpret_cast<const void * const*>(this);
    return reinterpret_cast<const uint32_t *>(asWords + offset);
  }

  bool isStaticallySpecializedGenericMetadata() const {
    auto *description = getDescription();
    if (!description->isGeneric())
      return false;

    auto *trailingFlags = getTrailingFlags();
    if (trailingFlags == nullptr)
      return false;

    return trailingFlags->isStaticSpecialization();
  }

  bool isCanonicalStaticallySpecializedGenericMetadata() const {
    auto *description = getDescription();
    if (!description->isGeneric())
      return false;

    auto *trailingFlags = getTrailingFlags();
    if (trailingFlags == nullptr)
      return false;

    return trailingFlags->isCanonicalStaticSpecialization();
  }

  const MetadataTrailingFlags *getTrailingFlags() const {
    auto description = getDescription();
    auto flags = description->getFullGenericContextHeader()
                     .DefaultInstantiationPattern->PatternFlags;
    if (!flags.hasTrailingFlags())
      return nullptr;
    auto fieldOffset = description->FieldOffsetVectorOffset;
    auto offset =
        fieldOffset +
        // Pad to the nearest pointer.
        ((description->NumFields * sizeof(uint32_t) + sizeof(void *) - 1) /
         sizeof(void *));
    auto asWords = reinterpret_cast<const void *const *>(this);
    return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
  }

  static constexpr int32_t getGenericArgumentOffset() {
    return sizeof(TargetStructMetadata<Runtime>) / sizeof(StoredPointer);
  }

  static bool classof(const TargetMetadata<Runtime> *metadata) {
    return metadata->getKind() == MetadataKind::Struct;
  }
};

我們發(fā)現(xiàn)TargetStructMetadataTargetEnumMetadata 如出一轍都是繼承自 TargetValueMetadata陷猫,通過之前對(duì) TargetEnumMetadata 的分析不難得出 TargetStructMetadata 的結(jié)構(gòu)為

struct TargetStructMetadata {
    var kind: Int
    var typeDescriptor: UnsafeMutablePointer<Any>
}

TargetEnumMetadata 不通過的是 TargetSructMetadatatypeDescriptor 的類型是 TargetStructDescriptor 定位到 TargetStructDescriptor

class TargetStructDescriptor final
    : public TargetValueTypeDescriptor<Runtime>,
      public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
                            TargetTypeGenericContextDescriptorHeader,
                            /*additional trailing objects*/
                            TargetForeignMetadataInitialization<Runtime>,
                            TargetSingletonMetadataInitialization<Runtime>,
                            TargetCanonicalSpecializedMetadatasListCount<Runtime>,
                            TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
                            TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
...
  /// The number of stored properties in the struct.
  /// If there is a field offset vector, this is its length.
  uint32_t NumFields;
  /// The offset of the field offset vector for this struct's stored
  /// properties in its metadata, if any. 0 means there is no field offset
  /// vector.
  uint32_t FieldOffsetVectorOffset;
  ...
};

發(fā)現(xiàn)跟 TargetEnumDescriptor 也差不太多都是繼承自 TargetValueTypeDescriptor 秫舌,只是屬性不一樣是 兩個(gè) uint32_t 類型的 NumFieldsFieldOffsetVectorOffset 這兩個(gè)屬性在 TargetClassDescriptor 中有
所以最后能夠得到 TargetSructMetadata 的最終數(shù)據(jù)結(jié)構(gòu)為

struct TargetStructMetadata {
    var kind: Int
    var typeDescriptor: UnsafeMutablePointer<TargetStructDescriptor>
}

struct TargetStructDescriptor {
    var flags: UInt32
    var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
    var name: TargetRelativeDirectPointer<CChar>
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
    var numFields: Int32
    // 每一個(gè)屬性值距離當(dāng)前實(shí)例對(duì)象地址的偏移量
    var fieldOffsetVectorOffset: Int32
    
    func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int32>{
      return metadata.assumingMemoryBound(to: Int32.self).advanced(by: numericCast(self.fieldOffsetVectorOffset) * 2)
    }
    
    var genericArgumentOffset: Int {
        return 2
    }
}
4.3.2 解析Struct的數(shù)據(jù)
struct Person {
    var age: Int = 18
    var name: String = "小明"
}

var person = Person()

let ptr = unsafeBitCast(Person.self as Any.Type, to: UnsafeMutablePointer<TargetStructMetadata>.self)

let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()
print("當(dāng)前結(jié)構(gòu)體的名稱: \(String(cString: namePtr))")


let numFileds = ptr.pointee.typeDescriptor.pointee.numFields
print("當(dāng)前結(jié)構(gòu)體屬性的個(gè)數(shù): \(numFileds)")

// 獲取偏移量
let offsets = ptr.pointee.typeDescriptor.pointee.getFieldOffsets(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self))

for i in 0..<numFileds{

    let fieldDespritor = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getApplyRelativeOffset()
    print("fieldDespritor: \(String(cString: fieldDespritor))")

    let fieldOffset = offsets[Int(i)]

    let typeMangleName = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getApplyRelativeOffset()

    // 獲取泛型參數(shù)
    let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)

    // 標(biāo)準(zhǔn)C語言函數(shù)庫
    let fieldType = swift_getTypeByMangledNameInContext(
        typeMangleName,
        256,
        UnsafeRawPointer(ptr.pointee.typeDescriptor),
        UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
    
    // 將fieldType轉(zhuǎn)換成Any類型
    let type = unsafeBitCast(fieldType, to: Any.Type.self)
    // 獲取實(shí)例對(duì)象p的指針 需要轉(zhuǎn)換成UnsafeRawPointer 并且綁定成1字節(jié)即Int8類型的妖,
    // 因?yàn)楹竺媸前醋止?jié)計(jì)算偏移量的,不轉(zhuǎn)換足陨,會(huì)以結(jié)構(gòu)體的長(zhǎng)度偏移
    let instanceAddress = withUnsafePointer(to: &person){
        return UnsafeRawPointer($0).assumingMemoryBound(to: Int8.self)
    }
    // 將屬性的類型信息綁定到協(xié)議的類型信息
    let valueType = customCast(type: type)
    // 獲取屬性值的地址的值
    let valueValue = valueType.get(from: instanceAddress.advanced(by: Int(fieldOffset)))
    
    print("fieldType:\(type) \nfieldValue:\(valueValue) ")
}

打印結(jié)果


Struct的數(shù)據(jù)的打印結(jié)果.png

自此通過對(duì)Mirror源碼的原理實(shí)現(xiàn)了對(duì) Enum 嫂粟、 ClassStruct 三種類型的解析小工具

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末墨缘,一起剝皮案震驚了整個(gè)濱河市星虹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌镊讼,老刑警劉巖宽涌,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異狠毯,居然都是意外死亡护糖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門嚼松,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嫡良,“玉大人,你說我怎么就攤上這事献酗∏奘埽” “怎么了?”我有些...
    開封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵罕偎,是天一觀的道長(zhǎng)很澄。 經(jīng)常有香客問我,道長(zhǎng)颜及,這世上最難降的妖魔是什么甩苛? 我笑而不...
    開封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮俏站,結(jié)果婚禮上讯蒲,老公的妹妹穿的比我還像新娘。我一直安慰自己肄扎,他們只是感情好墨林,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著犯祠,像睡著了一般旭等。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衡载,一...
    開封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天搔耕,我揣著相機(jī)與錄音,去河邊找鬼月劈。 笑死度迂,一個(gè)胖子當(dāng)著我的面吹牛藤乙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惭墓,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼坛梁,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了腊凶?” 一聲冷哼從身側(cè)響起划咐,我...
    開封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钧萍,沒想到半個(gè)月后褐缠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡风瘦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年队魏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片万搔。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡胡桨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞬雹,到底是詐尸還是另有隱情昧谊,我是刑警寧澤,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布酗捌,位于F島的核電站呢诬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏胖缤。R本人自食惡果不足惜尚镰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哪廓。 院中可真熱鬧钓猬,春花似錦、人聲如沸撩独。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽综膀。三九已至,卻和暖如春局齿,著一層夾襖步出監(jiān)牢的瞬間剧劝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工抓歼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留讥此,地道東北人拢锹。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像萄喳,于是被迫代替她去往敵國(guó)和親卒稳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容