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

一:元类型和 .self

1. AnyObject

AnyObject 代表任意类的实例,类的类型,仅类遵守的协议。

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 表示的就是一个实例对象,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

此时的协议 Myprotocol 后面的 AnyObject 就表示的遵守的协议,如果将 Class 换成 Struct 编译器就会报错,因此 AnyObject 是能代表仅类遵守的协议。

在编写代码的过程中,有时候不知道具体的类型,用 AnyObject 来表示

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

var p = Person()

var a: AnyObject = p.age as NSNumber

print(type(of: a))

// 打印结果
__NSCFNumber

如果确定了类型,使用三个关键字将 AnyObject 转换成具体的类型 asas?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")
}

// 打印结果
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

从上面打印结果和在汇编中的打印结果可以看出:
T 是实例对象,则 T.self 返回的就是他本身, T 是类,则 T.self 返回的就是元类型

class Person {
    var age: Int = 18
    var name: String = "小明"
    
    func test() {
        // self只当前实例对象
        print(self)
    }
    
    // 类方法
    static func test1() {
        // self 是 Person 这个类型本身
        print(self)
    }
}

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

self.png

在第一个断点处打印 self 得到当前实例对象,在第二个断点处打印 self 得到 Person 类本身。

3. Self

Self 类型不是特定的类型,而是方便地引用当前类型,而无需重复或知道该类型的名称。

  • 作为方法返回类型:Self 指代当前实例对象的类型
class Person {
    static let age = 18
    func test() -> Self{
        return self
    }
}
  • 作为协议中方法的返回类型:Self 指代遵循这个协议的类型
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 ,因为 Int 类型在 Swift 中是值类型,无法用 AnyObject 表示

5. AnyClass

AnyClass 代表任意实例的类型

AnyClass.png

可以看到 AnyClass 就是 AnyObjectType 类型

class Person {
    var age = 18
}

var t: AnyClass = Person.self

T.TypeT.self 的类型

二:Swift Runtime

我们都知道 Swift 是一门静态语言,但是在之前的文章 Swift探索(二): 类与结构体(下) 中提过 @objcNSObject@Objc dynamic 标识。那么是可以通过这些关键字来实现在 Swift中调用 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")
        }
    }
}

使用以上代码获取一个类的属性和方法

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

test(Person.self)

// 打印结果
空
  • 对于纯 Swift 类来说,方法和属性不加任何修饰符时。不具备 Runtime 特性。
class Person {
    @objc var age: Int = 18
    @objc func play() {
        print("play")
    }
}

test(Person.self)

// 打印结果
方法列表 :play
方法列表 :age
方法列表 :setAge:
属性成员属性:age
添加@objc.png
  • 对于纯 Swift 类,方法和属性添加 @objc 标识时,可以用过 RunTimeApi 拿到,但在 OC 中无法进行调度( LJLSwiftSimpleTest-Swift.h 中没有任何 Person 这个信息)。
class Person: NSObject {
    var age: Int = 18
    func play() {
        print("play")
    }
}

test(Person.self)

// 打印结果
方法列表 :init

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

test(Person.self)

// 打印结果
方法列表 :init
方法列表 :play
方法列表 :age
方法列表 :setAge:
属性成员属性:age
  • 对于继承自 NSObjectSwift 类,必须在声明属性和方法前添加 @objc 关键字才能动态的获取当前的属性和方法。
class Person {
    dynamic var age: Int = 18
    dynamic func play() {
        print("play")
    }
}

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

Person().play()
  • Swfit 没有动态性,但方法、属性前添加 dynamic 关键字,可获得动态性
class Person: NSObject {
    var age: Int = 18
    func play() {
        print("play")
    }
}

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

  • 继承自 NSObjectSwift 类,其继承自父类的方法具有动态性,其它自定义方法、属性相应获得动态性,需要添加 dynamic 修饰
    image.png
  • 若方法的参数、属性类型为 Swfit 特有无法映射到 OC的类型(如 CharacterTuple ),则此方法、属性无法添加 @objcdynamic 关键字(编译器报错)

三:Mirror

1. Mirror的基本用法

反射:就是动态获取类型、成员信息、在运行时可以调用方法、属性等行为的特性。
Swift 的反射机制是基于 Mirror 的结构体来实现的。可以为具体的实例创建一个 Mirror 对象,通过它来查询这个实例的属性、方法等。

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

var p = Person()

// 首先通过构造方法创建一个Mirror实例,  传入的参数是:Any, 也就意味着当前可以是类、结构体、枚举等
let mirror = Mirror(reflecting: p)
// 遍历 children 属性
for pro in mirror.children{
    // 通过 label 输出当前的名称, value 输出当前反射的值
    print("\(pro.label):\(pro.value)")
}

// 打印反射对象的类型
print("subjectType:\(mirror.subjectType)")

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

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

如果将 Person 换成 Stuct 那么最后 displayStyle 的打印结果是

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

2. Mirror的实际使用案例

func test(_ mirrorObj: Any) -> Any {
    
    let mirror = Mirror(reflecting: mirrorObj)
    // 如果当前实例对象的子属性为空 着返回当前实例
    guard !mirror.children.isEmpty else {
        return mirrorObj;
    }
    
    var result: [String: Any] = [:]
    // 遍历 children 属性
    for child in mirror.children{
        if let key = child.label {
            // 递归调用test方法, 直到当前的属性已经没有子属性了
            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)


// 打印结果
["age": 18, "name": "小明"]

这个例子只是简单的一个将实例对象的属性转换成字典。接下来编写一个功能完善的简易的模型转字典案例

// 定义一个协议
protocol LJLJsonMap {
    // 声明一个模型转字典的方法
    func jsonMap() throws -> Any
}

// 定义一个 错误枚举
enum JsonMapError: Error {
    case emptyKey // 没有属性名称
    case noProtocol // 没有遵守协议
}

// 定义一个扩展 实现 错误具体的返回
extension JsonMapError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .emptyKey:
            return "当前实例对象没有属性"
        case .noProtocol:
            return "当前实例对象的类型或属性的类型没有遵守协议"
        }
    }
}

// 定义一个扩展 具体实现 jsonMap()
extension LJLJsonMap {
    func jsonMap() throws -> Any {
        let mirror = Mirror(reflecting: self)
        // 如果当前实例对象的子属性为空 着返回当前实例
        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 {
                    // 递归调用jsonMap方法, 直到当前的属性已经没有子属性了
                    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 {}

// 因为 jsonMap 方法中递归调用 jsonMap 所以这几个类型都需要遵守 LJLJsonMap 协议
extension Int: LJLJsonMap{}
extension Double: LJLJsonMap{}

在上述代码的基础上执行一下代码

var pClass = PersonClass()

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

// 打印结果
["age": 18]
// 注意 Person2 中的 name 属性为 String 并且 String 没有遵守 LJLJsonMap 协议
var pClass = PersonClass2()

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

// 打印结果
当前实例对象的类型或属性的类型没有遵守协议
var pStruct = PersonStruct()

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

// 打印结果
["weight": 55.5]

3. Mirror源码窥探

首先在 Swift源码 中找到 Mirror.Swift 文件。在源码中我们可以看到 Mirror 是由结构体实现的

public struct Mirror {

找到初始化方法 init()

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

可以发现这里接收的是一个 Any 类型的参数。在方法体里有一个 if case 的判断语句,判断传入的 subject 是否遵循了 CustomReflectable 协议,如果是则直接调用 customMirror
对于 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
    }
}

实现这个 CustomReflectable 最直观的区别在 LLDB 调试时。

未实现CustomReflectable协议.png

实现了CustomReflectable协议.png

回到源码中,如果没有遵循 CustomReflectable 协议就进行下级的函数调用 Mirror(internalReflecting: subject)。通过这个函数可以定位到 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 的类型,前面调用这个函数的时候没有传入 subjectType 所以 subject 的类型是通过后面的 _getNormalizedType(subject, type: type(of: subject)) 的函数去获取的。

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

定位到 _getNormalizedType() 函数可以发现这里其实是调用的 C++ 的方法 swift_reflectionMirror_normalizedType。前面的 @_silgen_name 是编译器字段,是 Swift 一个隐藏的符号,作用是将 C/C++ 的函数直接映射为 Swift 函数。

// 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 函数是在 ReflectionMirror.cpp 文件中,发现这里返回的是 call 函数的调用,那么定位到 call 函数的实现,

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

发现这就是一个回调函数,回调的具体数据都是由 ReflectionMirrorImpl 结构体来实现的。定位到 ReflectionMirrorImpl 结构体

// 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() {}
};

可以发现 ReflectionMirrorImpl 是一个抽象类,也就意味着不同类型的反射都需要实现 ReflectionMirrorImpl 并且在 ReflectionMirror.cpp 文件的下方可以看到 TupleStructEnumClass 的具体实现。
StructImpl 的实现

// 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 进行强制转换,然后获取到 Matadata 中的 Description 再获取到 Description 中的 isRelectable 字段。

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

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

获取属性的数量,可以看到首先判断是否可以反射,不可以就返回 0 ,可以就还是将 StructMetadata 进行强制转换,然后获取到 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); 这句代码中调用了 getFieldAt

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

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

主要看这里,获取描述文件 Descriptor ,然后获取 Fieilds ,在获取到 Fieilds 中的属性的信息。在前面的文章 Swift探索(一): 类与结构体(上)Swift探索(二): 类与结构体(下) 当中我们提到过 StructClassEnum 都有自己的 Metadata , 并且 Metadata 中都有与之对应的 TypeDescriptor
通过对 TupleImplEnumImplClassImpl 的分析实现方式基本与 StructImpl 相同,都是通过 Matadata 类型的元数据、 getDescription 类型的描述 、 FieldDescrition 类型的属性的描述去实现。

4. 利用Mirror源码的原理实现解析小工具

首先通过源码分别获取到 EnumStructClass 这三种类型中的 Metadata

4.1 Enum 的实现
4.1.1 还原TargetEnumMetadata

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

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

我们发现这里面全是方法,并且 TargetEnumMetadata 继承自 TargetValueMetadata ,那么进入到 TargetValueMetadata

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

发现有一个属性 Description 并且 TargetValueMetadata 继承自 TargetMetadata ,进入到 TargetMetadata

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

发现有一个属性 Kind 由此可以推测出 TargetEnumMetadata 的结构为

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

可以看到这里进行了一个类型转换,转换成了 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;
  ...
};

发现 TargetEnumDescriptor 中有两个属性 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;
      
  ...
};

发现有三个 TargetRelativeDirectPointer 类型的的属性 NameAccessFunctionPtrFields ,并且 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;

  ...
};

发现 TargetContextDescriptor 是个基类,并且有两个属性 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))
  {}
  ...
};

发现 Flags 其实就是 uint32_t 类型,按位存储着 kindisGenericisUniqueversionkindSpecificFlags等信息。因此最终可以得出 TargetEnumDescriptor 具体的数据结构如下

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

可以看到这是一个别名的定义给 RelativeIndirectablePointer 取了一个别名 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();
  }
};

这个类主要作用是存储在内存中的对象的相对引用(相对引用指的是当前引用的内存地址,到当前对象的内存地址的距离)。通过 RelativeOffsetPlusIndirect 属性存储相对的地址偏移量,再通过 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() 函数中,会调用 applyRelativeOffset 函数,进行地址的偏移

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 中的返回可以发现返回的是 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>;

可以发现这里跟 TargetRelativeContextPointer 一样也是给 RelativeDirectPointer 取了一个别名 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;
};

发现这里调用的其实是 RelativeDirectPointerImpl 中的函数, 定位到 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;
  }
};

发现这里跟 TargetRelativeContextPointer 基本一样,都是存储在内存中的对象的相对引用,于是优化一下已经还原的 EnumMetadata 的结构体如下

// 传入指针
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 ,进入 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());
  }
};

可以发现有 RelativeDirectPointer 类型的属性 MangledTypeNameSuperclassFieldDescriptorKind 类型的属性 Kinduint16_t 类型的属性 FieldRecordSizeuint32_t 类型的属性 NumFields, 并且发现第一行代码中调用了一个方法通过 this+1 的方式一个一个的访问属性,所以这是一块连续的内存空间。进入 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();
  }
};

发现 FieldRecord 有三个属性 FieldRecordFlags 类型的 Flags 也就是 uint32_t类型、 RelativeDirectPointer 类型的 MangledTypeNameFieldName 。因此能够得到 fieldDescriptor 的结构体如下

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 最终数据结构

通过以上分析最终得到的 TargetEnumMetadata 数据结构如下

// 传入指针
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的数据
enum Week {
    case Mon
    case Tue
    case Wed
    case Thu
    case Fri
    case Sat
    case Sun
}

// 按位转换内存指针
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))
}

打印结果


Enum的数据打印结果.png
4.2 Class 的实现
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_tInstanceAddressPointInstanceSizeClassSizeClassAddressPoint 属性和 uint16_t 的 、 InstanceAlignMaskReserved 属性和 DescriptionIVarDestroyer 属性。进入到 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;
  ...
};

发现 TargetAnyClassMetadata 继承自 TargetHeapMetadata 并且有三个属性 SuperclassCacheDataData 。跳转到 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 跳转至 TargetMetadata

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

有一个属性 Kind, 根据以上源码分析可以得出 TargetClassMetadata 的数据结构

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 并且有 SuperclassTypeMetadataNegativeSizeInWordsMetadataPositiveSizeInWordsNumImmediateMembersNumFieldsFieldOffsetVectorOffset 属性,定位到 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 并且有 NameAccessFunctionPtrFields 属性, 定位到 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 属性。根据在上面对 Enum 数据结构的分析和 TargetClassMetadata 的源码分析,最后得出 TargetClassMetadata 的最终数据结构为

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
    // 每一个属性值距离当前实例对象地址的偏移量
    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的数据
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("当前类的名称: \(String(cString: namePtr))")

let numFileds = ptr.pointee.typeDescriptor.pointee.numFields
print("当前类属性的个数: \(numFileds)")

打印结果


Class的数据的打印结果.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()

    // 获取泛型参数
    let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)

    // 标准C语言函数库
    let fieldType = swift_getTypeByMangledNameInContext(
        typeMangleName,
        256,
        UnsafeRawPointer(ptr.pointee.typeDescriptor),
        UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
    
    // 将fieldType转换成Any类型
    let type = unsafeBitCast(fieldType, to: Any.Type.self)
    // 获取首地址
    let instanceAddress = Unmanaged.passUnretained(t as AnyObject).toOpaque()
    // 将属性的类型信息绑定到协议的类型信息
    let valueType = customCast(type: type)
    // 获取属性值的地址的值
    let valueValue = valueType.get(from: instanceAddress.advanced(by: fieldOffset))
    
    print("fieldType:\(type) \nfieldValue:\(valueValue) ")
}

其中 swift_getTypeByMangledNameInContext 是调用的C语言的标准函数这里通过swift桥接的形式进行

//typeNameStart 地址信息
//typeNameLength 名称混写长度信息
//context 上下文
//genericArgs 泛型参数
const void * _Nullable swift_getTypeByMangledNameInContext(
                        const char * _Nullable typeNameStart,
                        int typeNameLength,
                        const void * _Nullable context,
                        const void * _Nullable const * _Nullable genericArgs);

customCast(type: type) 具体内容为

protocol BrigeProtocol {}

extension BrigeProtocol {
    // 属性值的地址传入进来 后 返回属性值
    static func get(from pointer: UnsafeRawPointer) -> Any {
        pointer.assumingMemoryBound(to: Self.self).pointee
    }
}

// 协议的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
    // 按位强制转换成protocolType
    let cast = unsafeBitCast(container, to: protocolType)
    return cast
}

打印结果


Class的数据的打印结果.png
4.3 Struct 的实现
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;
  }
};

我们发现TargetStructMetadataTargetEnumMetadata 如出一辙都是继承自 TargetValueMetadata,通过之前对 TargetEnumMetadata 的分析不难得出 TargetStructMetadata 的结构为

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

发现跟 TargetEnumDescriptor 也差不太多都是继承自 TargetValueTypeDescriptor ,只是属性不一样是 两个 uint32_t 类型的 NumFieldsFieldOffsetVectorOffset 这两个属性在 TargetClassDescriptor 中有
所以最后能够得到 TargetSructMetadata 的最终数据结构为

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
    // 每一个属性值距离当前实例对象地址的偏移量
    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的数据
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("当前结构体的名称: \(String(cString: namePtr))")


let numFileds = ptr.pointee.typeDescriptor.pointee.numFields
print("当前结构体属性的个数: \(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()

    // 获取泛型参数
    let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)

    // 标准C语言函数库
    let fieldType = swift_getTypeByMangledNameInContext(
        typeMangleName,
        256,
        UnsafeRawPointer(ptr.pointee.typeDescriptor),
        UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
    
    // 将fieldType转换成Any类型
    let type = unsafeBitCast(fieldType, to: Any.Type.self)
    // 获取实例对象p的指针 需要转换成UnsafeRawPointer 并且绑定成1字节即Int8类型,
    // 因为后面是按字节计算偏移量的,不转换,会以结构体的长度偏移
    let instanceAddress = withUnsafePointer(to: &person){
        return UnsafeRawPointer($0).assumingMemoryBound(to: Int8.self)
    }
    // 将属性的类型信息绑定到协议的类型信息
    let valueType = customCast(type: type)
    // 获取属性值的地址的值
    let valueValue = valueType.get(from: instanceAddress.advanced(by: Int(fieldOffset)))
    
    print("fieldType:\(type) \nfieldValue:\(valueValue) ")
}

打印结果


Struct的数据的打印结果.png

自此通过对Mirror源码的原理实现了对 EnumClassStruct 三种类型的解析小工具

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容