一:元类型和 .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


可以看见
p1 的 AnyObject 表示的就是一个实例对象,p2 的 AnyObject 表示的就是原类型 Metadata
protocol Myprotocol: AnyObject {
}
class Person: Myprotocol {
var age: Int = 18
var name: String = "小明"
}
var p: Myprotocol = Person()
var p1: AnyObject = p

此时的协议
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 转换成具体的类型 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")
}
// 打印结果
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 是实例对象,则 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 得到当前实例对象,在第二个断点处打印 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 就是 AnyObject 的 Type 类型
class Person {
var age = 18
}
var t: AnyClass = Person.self
T.Type 是 T.self 的类型
二:Swift Runtime
我们都知道 Swift 是一门静态语言,但是在之前的文章 Swift探索(二): 类与结构体(下) 中提过 @objc 、NSObject、@Objc dynamic 标识。那么是可以通过这些关键字来实现在 Swift中调用 OC 中 Runtime 的 API 的。
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

- 对于纯
Swift类,方法和属性添加@objc标识时,可以用过RunTime的Api拿到,但在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
- 对于继承自
NSObject的Swift类,必须在声明属性和方法前添加@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")
}
}
- 继承自
NSObject的Swift类,其继承自父类的方法具有动态性,其它自定义方法、属性相应获得动态性,需要添加dynamic修饰
image.png - 若方法的参数、属性类型为
Swfit特有无法映射到OC的类型(如Character、Tuple),则此方法、属性无法添加@objc和dynamic关键字(编译器报错)
三: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 协议就进行下级的函数调用 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 文件的下方可以看到 Tuple 、 Struct 、 Enum 、 Class 的具体实现。
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探索(二): 类与结构体(下) 当中我们提到过 Struct 、 Class 、 Enum 都有自己的 Metadata , 并且 Metadata 中都有与之对应的 TypeDescriptor 。
通过对 TupleImpl 、 EnumImpl 、 ClassImpl 的分析实现方式基本与 StructImpl 相同,都是通过 Matadata 类型的元数据、 getDescription 类型的描述 、 FieldDescrition 类型的属性的描述去实现。
4. 利用Mirror源码的原理实现解析小工具
首先通过源码分别获取到 Enum 、 Struct 、 Class 这三种类型中的 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 NumPayloadCasesAndPayloadSizeOffset 和 uint32_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 类型的的属性 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;
...
};
发现 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 类型,按位存储着 kind 、 isGeneric 、 isUnique 、 version 、 kindSpecificFlags等信息。因此最终可以得出 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
}
接下来分析 TargetRelativeContextPointer 和 TargetRelativeDirectPointer 具体是什么
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 类型的属性 MangledTypeName 和 Superclass 、FieldDescriptorKind 类型的属性 Kind 、 uint16_t 类型的属性 FieldRecordSize 、 uint32_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 类型的 MangledTypeName 和 FieldName 。因此能够得到 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))
}
打印结果

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_t 的 InstanceAddressPoint 、 InstanceSize 、 ClassSize 、 ClassAddressPoint 属性和 uint16_t 的 、 InstanceAlignMask 、 Reserved 属性和 Description 、 IVarDestroyer 属性。进入到 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 并且有三个属性 Superclass 、 CacheData 、 Data 。跳转到 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 并且有 SuperclassType 、 MetadataNegativeSizeInWords 、 MetadataPositiveSizeInWords 、 NumImmediateMembers 、 NumFields 、 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 并且有 Name 、 AccessFunctionPtr 、 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;
...
};
TargetContextDescriptor 有 Flags 、 Parent 属性。根据在上面对 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)")
打印结果

再获取属性信息
// 获取偏移量
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
}
打印结果

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;
}
};
我们发现TargetStructMetadata 和 TargetEnumMetadata 如出一辙都是继承自 TargetValueMetadata,通过之前对 TargetEnumMetadata 的分析不难得出 TargetStructMetadata 的结构为
struct TargetStructMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer<Any>
}
与 TargetEnumMetadata 不通过的是 TargetSructMetadata 的 typeDescriptor 的类型是 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 类型的 NumFields 和 FieldOffsetVectorOffset 这两个属性在 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) ")
}
打印结果

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