一:元類型和 .self
1. AnyObject
AnyObject
代表任意類的實(shí)例,類的類型担忧,僅類遵守的協(xié)議芹缔。
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
var p1: AnyObject = p
var p2: AnyObject = Person.self
可以看見
p1
的 AnyObject
表示的就是一個(gè)實(shí)例對(duì)象,p2
的 AnyObject
表示的就是原類型 Metadata
protocol Myprotocol: AnyObject {
}
class Person: Myprotocol {
var age: Int = 18
var name: String = "小明"
}
var p: Myprotocol = Person()
var p1: AnyObject = p
此時(shí)的協(xié)議
Myprotocol
后面的 AnyObject
就表示的遵守的協(xié)議瓶盛,如果將 Class
換成 Struct
編譯器就會(huì)報(bào)錯(cuò)最欠,因此 AnyObject
是能代表僅類遵守的協(xié)議。
在編寫代碼的過程中惩猫,有時(shí)候不知道具體的類型芝硬,用 AnyObject
來表示
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
var a: AnyObject = p.age as NSNumber
print(type(of: a))
// 打印結(jié)果
__NSCFNumber
如果確定了類型,使用三個(gè)關(guān)鍵字將 AnyObject
轉(zhuǎn)換成具體的類型 as
轧房、 as?
拌阴、 as!
class Person {
var age: Int = 18
var name: String = "小明"
}
class SubPerson: Person {
var height: Double = 185.5
}
var p: AnyObject = SubPerson()
if let p1 = p as? Person {
print("\(p1) 是 Person")
}
// 打印結(jié)果
LJLSwiftSimpleTest.SubPerson 是 Person
2. T.self
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
var p1 = p.self
var p2 = p.self.self
var p3 = Person.self
從上面打印結(jié)果和在匯編中的打印結(jié)果可以看出:
T
是實(shí)例對(duì)象,則 T.self
返回的就是他本身奶镶, T
是類迟赃,則 T.self
返回的就是元類型
class Person {
var age: Int = 18
var name: String = "小明"
func test() {
// self只當(dāng)前實(shí)例對(duì)象
print(self)
}
// 類方法
static func test1() {
// self 是 Person 這個(gè)類型本身
print(self)
}
}
var p = Person()
p.test()
Person.test1()
在第一個(gè)斷點(diǎn)處打印
self
得到當(dāng)前實(shí)例對(duì)象,在第二個(gè)斷點(diǎn)處打印 self
得到 Person
類本身厂镇。
3. Self
Self
類型不是特定的類型纤壁,而是方便地引用當(dāng)前類型,而無需重復(fù)或知道該類型的名稱剪撬。
- 作為方法返回類型:
Self
指代當(dāng)前實(shí)例對(duì)象的類型
class Person {
static let age = 18
func test() -> Self{
return self
}
}
- 作為協(xié)議中方法的返回類型:
Self
指代遵循這個(gè)協(xié)議的類型
protocol MyProtocol {
func get() -> Self
}
class Person: MyProtocol {
func get() -> Self {
return self
}
}
4. Any
Any
代表任意類型摄乒,包括 function
類型或者 Optional
類型
var array: [Any] = [1, "小明", 3, false]
這里不能替換成 AnyObject
,因?yàn)?Int
類型在 Swift
中是值類型,無法用 AnyObject
表示
5. AnyClass
AnyClass
代表任意實(shí)例的類型
可以看到
AnyClass
就是 AnyObject
的 Type
類型
class Person {
var age = 18
}
var t: AnyClass = Person.self
T.Type
是 T.self
的類型
二:Swift Runtime
我們都知道 Swift
是一門靜態(tài)語言馍佑,但是在之前的文章 Swift探索(二): 類與結(jié)構(gòu)體(下) 中提過 @objc
斋否、NSObject
、@Objc dynamic
標(biāo)識(shí)拭荤。那么是可以通過這些關(guān)鍵字來實(shí)現(xiàn)在 Swift
中調(diào)用 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")
}
}
}
使用以上代碼獲取一個(gè)類的屬性和方法
class Person {
var age: Int = 18
func play() {
print("play")
}
}
test(Person.self)
// 打印結(jié)果
空
- 對(duì)于純
Swift
類來說,方法和屬性不加任何修飾符時(shí)舅世。不具備Runtime
特性旦委。
class Person {
@objc var age: Int = 18
@objc func play() {
print("play")
}
}
test(Person.self)
// 打印結(jié)果
方法列表 :play
方法列表 :age
方法列表 :setAge:
屬性成員屬性:age
- 對(duì)于純
Swift
類,方法和屬性添加@objc
標(biāo)識(shí)時(shí)雏亚,可以用過RunTime
的Api
拿到缨硝,但在OC
中無法進(jìn)行調(diào)度(LJLSwiftSimpleTest-Swift.h
中沒有任何Person
這個(gè)信息)。
class Person: NSObject {
var age: Int = 18
func play() {
print("play")
}
}
test(Person.self)
// 打印結(jié)果
方法列表 :init
class Person: NSObject {
@objc var age: Int = 18
@objc func play() {
print("play")
}
}
test(Person.self)
// 打印結(jié)果
方法列表 :init
方法列表 :play
方法列表 :age
方法列表 :setAge:
屬性成員屬性:age
- 對(duì)于繼承自
NSObject
的Swift
類罢低,必須在聲明屬性和方法前添加@objc
關(guān)鍵字才能動(dòng)態(tài)的獲取當(dāng)前的屬性和方法查辩。
class Person {
dynamic var age: Int = 18
dynamic func play() {
print("play")
}
}
extension Person {
@_dynamicReplacement(for: play) // 用play1()替代play()函數(shù)
func play1() {
print("play1")
}
}
Person().play()
- 純
Swfit
沒有動(dòng)態(tài)性,但方法网持、屬性前添加dynamic
關(guān)鍵字宜岛,可獲得動(dòng)態(tài)性
class Person: NSObject {
var age: Int = 18
func play() {
print("play")
}
}
class SubPerson: Person {
dynamic var name: String = "小明"
dynamic func play2() {
print("play2")
}
}
- 繼承自
NSObject
的Swift
類,其繼承自父類的方法具有動(dòng)態(tài)性功舀,其它自定義方法萍倡、屬性相應(yīng)獲得動(dòng)態(tài)性,需要添加dynamic
修飾
image.png - 若方法的參數(shù)辟汰、屬性類型為
Swfit
特有無法映射到OC
的類型(如Character
列敲、Tuple
),則此方法莉擒、屬性無法添加@objc
和dynamic
關(guān)鍵字(編譯器報(bào)錯(cuò))
三:Mirror
1. Mirror的基本用法
反射:就是動(dòng)態(tài)獲取類型酿炸、成員信息、在運(yùn)行時(shí)可以調(diào)用方法涨冀、屬性等行為的特性填硕。
Swift
的反射機(jī)制是基于 Mirror
的結(jié)構(gòu)體來實(shí)現(xiàn)的÷贡睿可以為具體的實(shí)例創(chuàng)建一個(gè) Mirror
對(duì)象扁眯,通過它來查詢這個(gè)實(shí)例的屬性、方法等翅帜。
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
// 首先通過構(gòu)造方法創(chuàng)建一個(gè)Mirror實(shí)例, 傳入的參數(shù)是:Any, 也就意味著當(dāng)前可以是類姻檀、結(jié)構(gòu)體、枚舉等
let mirror = Mirror(reflecting: p)
// 遍歷 children 屬性
for pro in mirror.children{
// 通過 label 輸出當(dāng)前的名稱, value 輸出當(dāng)前反射的值
print("\(pro.label):\(pro.value)")
}
// 打印反射對(duì)象的類型
print("subjectType:\(mirror.subjectType)")
// 打印反射的類型
print("displayStyle:\(mirror.displayStyle))")
// 打印結(jié)果
Optional("age"):18
Optional("name"):小明
subjectType:Person
displayStyle:Optional(Swift.Mirror.DisplayStyle.class))
如果將 Person
換成 Stuct
那么最后 displayStyle
的打印結(jié)果是
displayStyle:Optional(Swift.Mirror.DisplayStyle.struct))
2. Mirror的實(shí)際使用案例
func test(_ mirrorObj: Any) -> Any {
let mirror = Mirror(reflecting: mirrorObj)
// 如果當(dāng)前實(shí)例對(duì)象的子屬性為空 著返回當(dāng)前實(shí)例
guard !mirror.children.isEmpty else {
return mirrorObj;
}
var result: [String: Any] = [:]
// 遍歷 children 屬性
for child in mirror.children{
if let key = child.label {
// 遞歸調(diào)用test方法, 直到當(dāng)前的屬性已經(jīng)沒有子屬性了
result[key] = test(child.value)
} else {
print("no key")
}
}
return result
}
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
var result = test(p)
print(result)
// 打印結(jié)果
["age": 18, "name": "小明"]
這個(gè)例子只是簡(jiǎn)單的一個(gè)將實(shí)例對(duì)象的屬性轉(zhuǎn)換成字典涝滴。接下來編寫一個(gè)功能完善的簡(jiǎn)易的模型轉(zhuǎn)字典案例
// 定義一個(gè)協(xié)議
protocol LJLJsonMap {
// 聲明一個(gè)模型轉(zhuǎn)字典的方法
func jsonMap() throws -> Any
}
// 定義一個(gè) 錯(cuò)誤枚舉
enum JsonMapError: Error {
case emptyKey // 沒有屬性名稱
case noProtocol // 沒有遵守協(xié)議
}
// 定義一個(gè)擴(kuò)展 實(shí)現(xiàn) 錯(cuò)誤具體的返回
extension JsonMapError: LocalizedError {
var errorDescription: String? {
switch self {
case .emptyKey:
return "當(dāng)前實(shí)例對(duì)象沒有屬性"
case .noProtocol:
return "當(dāng)前實(shí)例對(duì)象的類型或?qū)傩缘念愋蜎]有遵守協(xié)議"
}
}
}
// 定義一個(gè)擴(kuò)展 具體實(shí)現(xiàn) jsonMap()
extension LJLJsonMap {
func jsonMap() throws -> Any {
let mirror = Mirror(reflecting: self)
// 如果當(dāng)前實(shí)例對(duì)象的子屬性為空 著返回當(dāng)前實(shí)例
guard !mirror.children.isEmpty else {
return self;
}
var result: [String: Any] = [:]
// 遍歷 children 屬性
for child in mirror.children {
if let value = child.value as? LJLJsonMap {
if let key = child.label {
// 遞歸調(diào)用jsonMap方法, 直到當(dāng)前的屬性已經(jīng)沒有子屬性了
result[key] = try value.jsonMap()
} else {
throw JsonMapError.emptyKey
}
} else {
throw JsonMapError.noProtocol
}
}
return result
}
}
class PersonClass {
var age: Int = 18
}
class PersonClass2 {
var name: String = "小明"
}
struct PersonStruct {
var weight: Double = 55.5
}
extension PersonClass: LJLJsonMap {}
extension PersonClass2: LJLJsonMap {}
extension PersonStruct: LJLJsonMap {}
// 因?yàn)?jsonMap 方法中遞歸調(diào)用 jsonMap 所以這幾個(gè)類型都需要遵守 LJLJsonMap 協(xié)議
extension Int: LJLJsonMap{}
extension Double: LJLJsonMap{}
在上述代碼的基礎(chǔ)上執(zhí)行一下代碼
var pClass = PersonClass()
do {
let resultClass = try pClass.jsonMap()
print(resultClass)
} catch {
print(error.localizedDescription.description)
}
// 打印結(jié)果
["age": 18]
// 注意 Person2 中的 name 屬性為 String 并且 String 沒有遵守 LJLJsonMap 協(xié)議
var pClass = PersonClass2()
do {
let result = try pClass.jsonMap()
print(result)
} catch {
print(error.localizedDescription.description)
}
// 打印結(jié)果
當(dāng)前實(shí)例對(duì)象的類型或?qū)傩缘念愋蜎]有遵守協(xié)議
var pStruct = PersonStruct()
do {
let result = try pStruct.jsonMap()
print(result)
} catch {
print(error.localizedDescription.description)
}
// 打印結(jié)果
["weight": 55.5]
3. Mirror源碼窺探
首先在 Swift源碼 中找到 Mirror.Swift
文件绣版。在源碼中我們可以看到 Mirror
是由結(jié)構(gòu)體實(shí)現(xiàn)的
public struct Mirror {
找到初始化方法 init()
public init(reflecting subject: Any) {
if case let customized as CustomReflectable = subject {
self = customized.customMirror
} else {
self = Mirror(internalReflecting: subject)
}
}
可以發(fā)現(xiàn)這里接收的是一個(gè) Any
類型的參數(shù)胶台。在方法體里有一個(gè) if case
的判斷語句,判斷傳入的 subject
是否遵循了 CustomReflectable
協(xié)議杂抽,如果是則直接調(diào)用 customMirror
對(duì)于 CustomReflectable
的用法如下
class Person: CustomReflectable {
var age: Int
var name: String
init(_ age: Int, _ name: String) {
self.age = age
self.name = name
}
var customMirror: Mirror {
let info = KeyValuePairs<String, Any>.init(dictionaryLiteral: ("age", age), ("name", name))
let mirror = Mirror.init(self, children: info, displayStyle: .class, ancestorRepresentation: .generated)
return mirror
}
}
實(shí)現(xiàn)這個(gè) CustomReflectable
最直觀的區(qū)別在 LLDB
調(diào)試時(shí)诈唬。
回到源碼中,如果沒有遵循
CustomReflectable
協(xié)議就進(jìn)行下級(jí)的函數(shù)調(diào)用 Mirror(internalReflecting: subject)
缩麸。通過這個(gè)函數(shù)可以定位到 ReflectionMirror.swift
文件中的 init(internalReflecting subject: Any, subjectType: Any.Type? = nil, customAncestor: Mirror? = nil)
方法
internal init(internalReflecting subject: Any,
subjectType: Any.Type? = nil,
customAncestor: Mirror? = nil)
{
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
let childCount = _getChildCount(subject, type: subjectType)
let children = (0 ..< childCount).lazy.map({
getChild(of: subject, type: subjectType, index: $0)
})
self.children = Children(children)
self._makeSuperclassMirror = {
guard let subjectClass = subjectType as? AnyClass,
let superclass = _getSuperclass(subjectClass) else {
return nil
}
// Handle custom ancestors. If we've hit the custom ancestor's subject type,
// or descendants are suppressed, return it. Otherwise continue reflecting.
if let customAncestor = customAncestor {
if superclass == customAncestor.subjectType {
return customAncestor
}
if customAncestor._defaultDescendantRepresentation == .suppressed {
return customAncestor
}
}
return Mirror(internalReflecting: subject,
subjectType: superclass,
customAncestor: customAncestor)
}
let rawDisplayStyle = _getDisplayStyle(subject)
switch UnicodeScalar(Int(rawDisplayStyle)) {
case "c": self.displayStyle = .class
case "e": self.displayStyle = .enum
case "s": self.displayStyle = .struct
case "t": self.displayStyle = .tuple
case "\0": self.displayStyle = nil
default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
}
self.subjectType = subjectType
self._defaultDescendantRepresentation = .generated
}
首先第一步
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
這里是獲取 subject
的類型铸磅,前面調(diào)用這個(gè)函數(shù)的時(shí)候沒有傳入 subjectType
所以 subject
的類型是通過后面的 _getNormalizedType(subject, type: type(of: subject))
的函數(shù)去獲取的。
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
定位到 _getNormalizedType()
函數(shù)可以發(fā)現(xiàn)這里其實(shí)是調(diào)用的 C++
的方法 swift_reflectionMirror_normalizedType
杭朱。前面的 @_silgen_name
是編譯器字段阅仔,是 Swift
一個(gè)隱藏的符號(hào),作用是將 C/C++
的函數(shù)直接映射為 Swift
函數(shù)弧械。
// func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}
找到 swift_reflectionMirror_normalizedType
函數(shù)是在 ReflectionMirror.cpp
文件中八酒,發(fā)現(xiàn)這里返回的是 call
函數(shù)的調(diào)用,那么定位到 call
函數(shù)的實(shí)現(xiàn)梦谜,
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
const F &f) -> decltype(f(nullptr))
{
const Metadata *type;
OpaqueValue *value;
std::tie(type, value) = unwrapExistential(T, passedValue);
if (passedType != nullptr) {
type = passedType;
}
auto call = [&](ReflectionMirrorImpl *impl) {
impl->type = type;
impl->value = value;
auto result = f(impl);
return result;
};
...
}
發(fā)現(xiàn)這就是一個(gè)回調(diào)函數(shù)丘跌,回調(diào)的具體數(shù)據(jù)都是由 ReflectionMirrorImpl
結(jié)構(gòu)體來實(shí)現(xiàn)的。定位到 ReflectionMirrorImpl
結(jié)構(gòu)體
// Abstract base class for reflection implementations.
struct ReflectionMirrorImpl {
const Metadata *type;
OpaqueValue *value;
virtual char displayStyle() = 0;
virtual intptr_t count() = 0;
virtual intptr_t childOffset(intptr_t index) = 0;
virtual const FieldType childMetadata(intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *)) = 0;
virtual AnyReturn subscript(intptr_t index, const char **outName,
void (**outFreeFunc)(const char *)) = 0;
virtual const char *enumCaseName() { return nullptr; }
#if SWIFT_OBJC_INTEROP
virtual id quickLookObject() { return nil; }
#endif
// For class types, traverse through superclasses when providing field
// information. The base implementations call through to their local-only
// counterparts.
virtual intptr_t recursiveCount() {
return count();
}
virtual intptr_t recursiveChildOffset(intptr_t index) {
return childOffset(index);
}
virtual const FieldType recursiveChildMetadata(intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *))
{
return childMetadata(index, outName, outFreeFunc);
}
virtual ~ReflectionMirrorImpl() {}
};
可以發(fā)現(xiàn) ReflectionMirrorImpl
是一個(gè)抽象類唁桩,也就意味著不同類型的反射都需要實(shí)現(xiàn) ReflectionMirrorImpl
并且在 ReflectionMirror.cpp
文件的下方可以看到 Tuple
、 Struct
耸棒、 Enum
荒澡、 Class
的具體實(shí)現(xiàn)。
StructImpl
的實(shí)現(xiàn)
// Implementation for structs.
struct StructImpl : ReflectionMirrorImpl {
bool isReflectable() {
const auto *Struct = static_cast<const StructMetadata *>(type);
const auto &Description = Struct->getDescription();
return Description->isReflectable();
}
char displayStyle() override {
return 's';
}
intptr_t count() override {
if (!isReflectable()) {
return 0;
}
auto *Struct = static_cast<const StructMetadata *>(type);
return Struct->getDescription()->NumFields;
}
intptr_t childOffset(intptr_t i) override {
auto *Struct = static_cast<const StructMetadata *>(type);
if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
// Load the offset from its respective vector.
return Struct->getFieldOffsets()[i];
}
const FieldType childMetadata(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
*outName = name.data();
*outFreeFunc = nullptr;
return fieldInfo;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
auto fieldInfo = childMetadata(i, outName, outFreeFunc);
auto *bytes = reinterpret_cast<char*>(value);
auto fieldOffset = childOffset(i);
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
return copyFieldContents(fieldData, fieldInfo);
}
};
bool isReflectable() {
const auto *Struct = static_cast<const StructMetadata *>(type);
const auto &Description = Struct->getDescription();
return Description->isReflectable();
}
獲取是否可以反射与殃,可以看到這里面首先將 StructMetadata
進(jìn)行強(qiáng)制轉(zhuǎn)換单山,然后獲取到 Matadata
中的 Description
再獲取到 Description
中的 isRelectable
字段。
intptr_t count() override {
if (!isReflectable()) {
return 0;
}
auto *Struct = static_cast<const StructMetadata *>(type);
return Struct->getDescription()->NumFields;
}
獲取屬性的數(shù)量幅疼,可以看到首先判斷是否可以反射米奸,不可以就返回 0
,可以就還是將 StructMetadata
進(jìn)行強(qiáng)制轉(zhuǎn)換窥浪,然后獲取到 Description
中的 NumFields
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
auto fieldInfo = childMetadata(i, outName, outFreeFunc);
auto *bytes = reinterpret_cast<char*>(value);
auto fieldOffset = childOffset(i);
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
return copyFieldContents(fieldData, fieldInfo);
}
可以看到 fieldInfo
是通過 childMetadata()
獲取
const FieldType childMetadata(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
*outName = name.data();
*outFreeFunc = nullptr;
return fieldInfo;
}
可以看到 std::tie(name, fieldInfo) = getFieldAt(type, i);
這句代碼中調(diào)用了 getFieldAt
getFieldAt(const Metadata *base, unsigned index) {
...
auto *baseDesc = base->getTypeContextDescriptor();
if (!baseDesc)
return failedToFindMetadata();
auto *fields = baseDesc->Fields.get();
...
}
主要看這里掺逼,獲取描述文件 Descriptor
娇澎,然后獲取 Fieilds
,在獲取到 Fieilds
中的屬性的信息铡溪。在前面的文章 Swift探索(一): 類與結(jié)構(gòu)體(上)和 Swift探索(二): 類與結(jié)構(gòu)體(下) 當(dāng)中我們提到過 Struct
、 Class
泪喊、 Enum
都有自己的 Metadata
棕硫, 并且 Metadata
中都有與之對(duì)應(yīng)的 TypeDescriptor
。
通過對(duì) TupleImpl
袒啼、 EnumImpl
哈扮、 ClassImpl
的分析實(shí)現(xiàn)方式基本與 StructImpl
相同纬纪,都是通過 Matadata
類型的元數(shù)據(jù)、 getDescription
類型的描述 滑肉、 FieldDescrition
類型的屬性的描述去實(shí)現(xiàn)育八。
4. 利用Mirror源碼的原理實(shí)現(xiàn)解析小工具
首先通過源碼分別獲取到 Enum
、 Struct
赦邻、 Class
這三種類型中的 Metadata
髓棋。
4.1 Enum 的實(shí)現(xiàn)
4.1.1 還原TargetEnumMetadata
首先定位到源碼中的 Metadata.h
文件中,找到 TargetEnumMetadata
代碼如下
struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
// 全是方法
...
}
我們發(fā)現(xiàn)這里面全是方法惶洲,并且 TargetEnumMetadata
繼承自 TargetValueMetadata
按声,那么進(jìn)入到 TargetValueMetadata
中
struct TargetValueMetadata : public TargetMetadata<Runtime> {
...
/// An out-of-line description of the type.
TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
...
};
發(fā)現(xiàn)有一個(gè)屬性 Description
并且 TargetValueMetadata
繼承自 TargetMetadata
,進(jìn)入到 TargetMetadata
struct TargetMetadata {
...
private:
/// The kind. Only valid for non-class metadata; getKind() must be used to get
/// the kind value.
StoredPointer Kind;
...
};
發(fā)現(xiàn)有一個(gè)屬性 Kind
由此可以推測(cè)出 TargetEnumMetadata
的結(jié)構(gòu)為
struct TargetEnumMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer<Any>
}
4.1.2 還原typeDescriptor
其中 typeDescriptor
就是枚舉 metadata
的描述信息恬吕,回到源碼的 TargetEnumMetadata
中
struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
using StoredPointer = typename Runtime::StoredPointer;
using StoredSize = typename Runtime::StoredSize;
using TargetValueMetadata<Runtime>::TargetValueMetadata;
const TargetEnumDescriptor<Runtime> *getDescription() const {
return llvm::cast<TargetEnumDescriptor<Runtime>>(this->Description);
}
...
};
可以看到這里進(jìn)行了一個(gè)類型轉(zhuǎn)換签则,轉(zhuǎn)換成了 TargetEnumDescriptor
,定位到 TargetEnumDescriptor
class TargetEnumDescriptor final
: public TargetValueTypeDescriptor<Runtime>,
public TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
TargetTypeGenericContextDescriptorHeader,
/*additional trailing objects*/
TargetForeignMetadataInitialization<Runtime>,
TargetSingletonMetadataInitialization<Runtime>,
TargetCanonicalSpecializedMetadatasListCount<Runtime>,
TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
...
/// The number of non-empty cases in the enum are in the low 24 bits;
/// the offset of the payload size in the metadata record in words,
/// if any, is stored in the high 8 bits.
uint32_t NumPayloadCasesAndPayloadSizeOffset;
/// The number of empty cases in the enum.
uint32_t NumEmptyCases;
...
};
發(fā)現(xiàn) TargetEnumDescriptor
中有兩個(gè)屬性 uint32_t 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;
...
};
發(fā)現(xiàn)有三個(gè) TargetRelativeDirectPointer
類型的的屬性 Name
钠惩、 AccessFunctionPtr
柒凉、 Fields
,并且 TargetTypeContextDescriptor
繼承自 TargetContextDescriptor
篓跛,定位到 TargetContextDescriptor
struct TargetContextDescriptor {
/// Flags describing the context, including its kind and format version.
ContextDescriptorFlags Flags;
/// The parent context, or null if this is a top-level context.
TargetRelativeContextPointer<Runtime> Parent;
...
};
發(fā)現(xiàn) TargetContextDescriptor
是個(gè)基類膝捞,并且有兩個(gè)屬性 ContextDescriptorFlags
類型的 Flags
,和 TargetRelativeContextPointer
類型的 Parent
愧沟, 定位到 ContextDescriptorFlags
中
struct ContextDescriptorFlags {
private:
uint32_t Value;
explicit constexpr ContextDescriptorFlags(uint32_t Value)
: Value(Value) {}
public:
constexpr ContextDescriptorFlags() : Value(0) {}
constexpr ContextDescriptorFlags(ContextDescriptorKind kind,
bool isGeneric,
bool isUnique,
uint8_t version,
uint16_t kindSpecificFlags)
: ContextDescriptorFlags(ContextDescriptorFlags()
.withKind(kind)
.withGeneric(isGeneric)
.withUnique(isUnique)
.withVersion(version)
.withKindSpecificFlags(kindSpecificFlags))
{}
...
};
發(fā)現(xiàn) Flags
其實(shí)就是 uint32_t
類型蔬咬,按位存儲(chǔ)著 kind
、 isGeneric
沐寺、 isUnique
林艘、 version
、 kindSpecificFlags
等信息混坞。因此最終可以得出 TargetEnumDescriptor
具體的數(shù)據(jù)結(jié)構(gòu)如下
struct TargetEnumDescriptor {
var flags: UInt32
var parent: TargetRelativeContextPointer<UnsafeRawPointer>
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<UnsafeRawPointer>
var numPayloadCasesAndPayloadSizeOffset: UInt32
var numEmptyCases: UInt32
}
接下來分析 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>>;
可以看到這是一個(gè)別名的定義給 RelativeIndirectablePointer
取了一個(gè)別名 TargetRelativeContextPointer
狐援, 定位到 RelativeIndirectablePointer
/// A relative reference to an object stored in memory. The reference may be
/// direct or indirect, and uses the low bit of the (assumed at least
/// 2-byte-aligned) pointer to differentiate.
template<typename ValueTy, bool Nullable = false, typename Offset = int32_t, typename IndirectType = const ValueTy *>
class RelativeIndirectablePointer {
private:
static_assert(std::is_integral<Offset>::value &&
std::is_signed<Offset>::value,
"offset type should be signed integer");
/// The relative offset of the pointer's memory from the `this` pointer.
/// If the low bit is clear, this is a direct reference; otherwise, it is
/// an indirect reference.
Offset RelativeOffsetPlusIndirect;
/// RelativePointers should appear in statically-generated metadata. They
/// shouldn't be constructed or copied.
RelativeIndirectablePointer() = delete;
RelativeIndirectablePointer(RelativeIndirectablePointer &&) = delete;
RelativeIndirectablePointer(const RelativeIndirectablePointer &) = delete;
RelativeIndirectablePointer &operator=(RelativeIndirectablePointer &&)
= delete;
RelativeIndirectablePointer &operator=(const RelativeIndirectablePointer &)
= delete;
public:
/// Allow construction and reassignment from an absolute pointer.
/// These always produce a direct relative offset.
RelativeIndirectablePointer(ValueTy *absolute)
: RelativeOffsetPlusIndirect(
Nullable && absolute == nullptr
? 0
: detail::measureRelativeOffset<Offset>(absolute, this)) {
if (!Nullable)
assert(absolute != nullptr &&
"constructing non-nullable relative pointer from null");
}
RelativeIndirectablePointer &operator=(ValueTy *absolute) & {
if (!Nullable)
assert(absolute != nullptr &&
"constructing non-nullable relative pointer from null");
RelativeOffsetPlusIndirect = Nullable && absolute == nullptr
? 0
: detail::measureRelativeOffset<Offset>(absolute, this);
return *this;
}
const ValueTy *get() const & {
static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
"alignment of value and offset must be at least 2 to "
"make room for indirectable flag");
// Check for null.
if (Nullable && RelativeOffsetPlusIndirect == 0)
return nullptr;
Offset offsetPlusIndirect = RelativeOffsetPlusIndirect;
uintptr_t address = detail::applyRelativeOffset(this,
offsetPlusIndirect & ~1);
// If the low bit is set, then this is an indirect address. Otherwise,
// it's direct.
if (offsetPlusIndirect & 1) {
return *reinterpret_cast<IndirectType const *>(address);
} else {
return reinterpret_cast<const ValueTy *>(address);
}
}
/// A zero relative offset encodes a null reference.
bool isNull() const & {
return RelativeOffsetPlusIndirect == 0;
}
operator const ValueTy* () const & {
return get();
}
const ValueTy *operator->() const & {
return get();
}
};
這個(gè)類主要作用是存儲(chǔ)在內(nèi)存中的對(duì)象的相對(duì)引用(相對(duì)引用指的是當(dāng)前引用的內(nèi)存地址,到當(dāng)前對(duì)象的內(nèi)存地址的距離)拔第。通過 RelativeOffsetPlusIndirect
屬性存儲(chǔ)相對(duì)的地址偏移量咕村,再通過 get()
方法獲取。
const ValueTy *get() const & {
static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
"alignment of value and offset must be at least 2 to "
"make room for indirectable flag");
// Check for null.
if (Nullable && RelativeOffsetPlusIndirect == 0)
return nullptr;
Offset offsetPlusIndirect = RelativeOffsetPlusIndirect;
uintptr_t address = detail::applyRelativeOffset(this,
offsetPlusIndirect & ~1);
// If the low bit is set, then this is an indirect address. Otherwise,
// it's direct.
if (offsetPlusIndirect & 1) {
return *reinterpret_cast<IndirectType const *>(address);
} else {
return reinterpret_cast<const ValueTy *>(address);
}
}
在 get()
函數(shù)中蚊俺,會(huì)調(diào)用 applyRelativeOffset
函數(shù)懈涛,進(jìn)行地址的偏移
static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
static_assert(std::is_integral<Offset>::value &&
std::is_signed<Offset>::value,
"offset type should be signed integer");
auto base = reinterpret_cast<uintptr_t>(basePtr);
// We want to do wrapping arithmetic, but with a sign-extended
// offset. To do this in C, we need to do signed promotion to get
// the sign extension, but we need to perform arithmetic on unsigned values,
// since signed overflow is undefined behavior.
auto extendOffset = (uintptr_t)(intptr_t)offset;
return base + extendOffset;
}
在 applyRelativeOffset
中的返回可以發(fā)現(xiàn)返回的是 base + extendOffset
基地址加上偏移的值。因此 TargetRelativeContextPointer
可以通過 Swift
代碼還原
// 傳入指針
struct TargetRelativeContextPointer <Pointee>{
var offset: Int32
mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
// 獲取指針地址 偏移offset后 重新綁定為傳入的指針的類型
let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
return UnsafeMutablePointer(mutating: pointer)
}
}
}
4.1.4 還原TargetRelativeDirectPointer
定位到 TargetRelativeDirectPointer
template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeDirectPointer
= typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
可以發(fā)現(xiàn)這里跟 TargetRelativeContextPointer
一樣也是給 RelativeDirectPointer
取了一個(gè)別名 TargetRelativeDirectPointer
泳猬, 定位到 RelativeDirectPointer
/// A direct relative reference to an object that is not a function pointer.
template <typename T, bool Nullable, typename Offset>
class RelativeDirectPointer<T, Nullable, Offset,
typename std::enable_if<!std::is_function<T>::value>::type>
: private RelativeDirectPointerImpl<T, Nullable, Offset>
{
using super = RelativeDirectPointerImpl<T, Nullable, Offset>;
public:
using super::get;
using super::super;
RelativeDirectPointer &operator=(T *absolute) & {
super::operator=(absolute);
return *this;
}
operator typename super::PointerTy() const & {
return this->get();
}
const typename super::ValueTy *operator->() const & {
return this->get();
}
using super::isNull;
};
發(fā)現(xiàn)這里調(diào)用的其實(shí)是 RelativeDirectPointerImpl
中的函數(shù)批钠, 定位到 RelativeDirectPointerImpl
/// A relative reference to a function, intended to reference private metadata
/// functions for the current executable or dynamic library image from
/// position-independent constant data.
template<typename T, bool Nullable, typename Offset>
class RelativeDirectPointerImpl {
private:
/// The relative offset of the function's entry point from *this.
Offset RelativeOffset;
/// RelativePointers should appear in statically-generated metadata. They
/// shouldn't be constructed or copied.
RelativeDirectPointerImpl() = delete;
/// RelativePointers should appear in statically-generated metadata. They
/// shouldn't be constructed or copied.
RelativeDirectPointerImpl(RelativeDirectPointerImpl &&) = delete;
RelativeDirectPointerImpl(const RelativeDirectPointerImpl &) = delete;
RelativeDirectPointerImpl &operator=(RelativeDirectPointerImpl &&)
= delete;
RelativeDirectPointerImpl &operator=(const RelativeDirectPointerImpl &)
= delete;
public:
using ValueTy = T;
using PointerTy = T*;
// Allow construction and reassignment from an absolute pointer.
RelativeDirectPointerImpl(PointerTy absolute)
: RelativeOffset(Nullable && absolute == nullptr
? 0
: detail::measureRelativeOffset<Offset>(absolute, this))
{
if (!Nullable)
assert(absolute != nullptr &&
"constructing non-nullable relative pointer from null");
}
explicit constexpr RelativeDirectPointerImpl(std::nullptr_t)
: RelativeOffset (0) {
static_assert(Nullable, "can't construct non-nullable pointer from null");
}
RelativeDirectPointerImpl &operator=(PointerTy absolute) & {
if (!Nullable)
assert(absolute != nullptr &&
"constructing non-nullable relative pointer from null");
RelativeOffset = Nullable && absolute == nullptr
? 0
: detail::measureRelativeOffset<Offset>(absolute, this);
return *this;
}
PointerTy get() const & {
// Check for null.
if (Nullable && RelativeOffset == 0)
return nullptr;
// The value is addressed relative to `this`.
uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
return reinterpret_cast<PointerTy>(absolute);
}
/// A zero relative offset encodes a null reference.
bool isNull() const & {
return RelativeOffset == 0;
}
};
發(fā)現(xiàn)這里跟 TargetRelativeContextPointer
基本一樣宇植,都是存儲(chǔ)在內(nèi)存中的對(duì)象的相對(duì)引用,于是優(yōu)化一下已經(jīng)還原的 EnumMetadata
的結(jié)構(gòu)體如下
// 傳入指針
struct TargetRelativeDirectPointer<Pointee>{
var offset: Int32
mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
// 獲取指針地址 偏移offset后 重新綁定為傳入的指針的類型
let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
return UnsafeMutablePointer(mutating: pointer)
}
}
}
struct TargetEnumMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer<TargetEnumDescriptor>
}
struct TargetEnumDescriptor {
var flags: UInt32
var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<UnsafeRawPointer>
var numPayloadCasesAndPayloadSizeOffset: UInt32
var numEmptyCases: UInt32
}
4.1.5 還原fieldDescriptor
在源碼中
class TargetTypeContextDescriptor
: public TargetContextDescriptor<Runtime> {
public:
...
/// A pointer to the field descriptor for the type, if any.
TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
/*nullable*/ true> Fields;
...
};
注意到這里使用的命名空間中的 FieldDescriptor
埋心,進(jìn)入 FieldDescriptor
class FieldDescriptor {
const FieldRecord *getFieldRecordBuffer() const {
return reinterpret_cast<const FieldRecord *>(this + 1);
}
public:
const RelativeDirectPointer<const char> MangledTypeName;
const RelativeDirectPointer<const char> Superclass;
FieldDescriptor() = delete;
const FieldDescriptorKind Kind;
const uint16_t FieldRecordSize;
const uint32_t NumFields;
using const_iterator = FieldRecordIterator;
bool isEnum() const {
return (Kind == FieldDescriptorKind::Enum ||
Kind == FieldDescriptorKind::MultiPayloadEnum);
}
bool isClass() const {
return (Kind == FieldDescriptorKind::Class ||
Kind == FieldDescriptorKind::ObjCClass);
}
bool isProtocol() const {
return (Kind == FieldDescriptorKind::Protocol ||
Kind == FieldDescriptorKind::ClassProtocol ||
Kind == FieldDescriptorKind::ObjCProtocol);
}
bool isStruct() const {
return Kind == FieldDescriptorKind::Struct;
}
const_iterator begin() const {
auto Begin = getFieldRecordBuffer();
auto End = Begin + NumFields;
return const_iterator { Begin, End };
}
const_iterator end() const {
auto Begin = getFieldRecordBuffer();
auto End = Begin + NumFields;
return const_iterator { End, End };
}
llvm::ArrayRef<FieldRecord> getFields() const {
return {getFieldRecordBuffer(), NumFields};
}
bool hasMangledTypeName() const {
return MangledTypeName;
}
StringRef getMangledTypeName() const {
return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get());
}
bool hasSuperclass() const {
return Superclass;
}
StringRef getSuperclass() const {
return Demangle::makeSymbolicMangledNameStringRef(Superclass.get());
}
};
可以發(fā)現(xiàn)有 RelativeDirectPointer
類型的屬性 MangledTypeName
和 Superclass
指郁、FieldDescriptorKind
類型的屬性 Kind
、 uint16_t
類型的屬性 FieldRecordSize
拷呆、 uint32_t
類型的屬性 NumFields
闲坎, 并且發(fā)現(xiàn)第一行代碼中調(diào)用了一個(gè)方法通過 this+1
的方式一個(gè)一個(gè)的訪問屬性,所以這是一塊連續(xù)的內(nèi)存空間茬斧。進(jìn)入 FieldRecord
class FieldRecord {
const FieldRecordFlags Flags;
public:
const RelativeDirectPointer<const char> MangledTypeName;
const RelativeDirectPointer<const char> FieldName;
FieldRecord() = delete;
bool hasMangledTypeName() const {
return MangledTypeName;
}
StringRef getMangledTypeName() const {
return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get());
}
StringRef getFieldName() const {
return FieldName.get();
}
bool isIndirectCase() const {
return Flags.isIndirectCase();
}
bool isVar() const {
return Flags.isVar();
}
};
發(fā)現(xiàn) FieldRecord
有三個(gè)屬性 FieldRecordFlags
類型的 Flags
也就是 uint32_t
類型腰懂、 RelativeDirectPointer
類型的 MangledTypeName
和 FieldName
。因此能夠得到 fieldDescriptor
的結(jié)構(gòu)體如下
struct FieldDescriptor {
var mangledTypeName: TargetRelativeDirectPointer<CChar>
var superclass: TargetRelativeDirectPointer<CChar>
var kind: UInt16
var fieldRecordSize: Int16
var numFields: Int32
var fields: FiledRecordBuffer<FieldRecord>
}
struct FieldRecord {
var fieldRecordFlags: Int32
var mangledTypeName: TargetRelativeDirectPointer<CChar>
var fieldName: TargetRelativeDirectPointer<UInt8>
}
struct FiledRecordBuffer<Element>{
var element: Element
mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
return withUnsafePointer(to: &self) {
let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
return start
}
return UnsafeBufferPointer(start: ptr, count: n)
}
}
mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
}
}
}
4.1.6 TargetEnumMetadata 最終數(shù)據(jù)結(jié)構(gòu)
通過以上分析最終得到的 TargetEnumMetadata
數(shù)據(jù)結(jié)構(gòu)如下
// 傳入指針
struct TargetRelativeDirectPointer<Pointee>{
var offset: Int32
mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
// 獲取指針地址 偏移offset后 重新綁定為傳入的指針的類型
let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
return UnsafeMutablePointer(mutating: pointer)
}
}
}
struct TargetEnumMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer<TargetEnumDescriptor>
}
struct TargetEnumDescriptor {
var flags: UInt32
var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
var numPayloadCasesAndPayloadSizeOffset: UInt32
var numEmptyCases: UInt32
}
struct FieldDescriptor {
var mangledTypeName: TargetRelativeDirectPointer<CChar>
var superclass: TargetRelativeDirectPointer<CChar>
var kind: UInt16
var fieldRecordSize: Int16
var numFields: Int32
var fields: FiledRecordBuffer<FieldRecord>
}
struct FieldRecord {
var fieldRecordFlags: UInt32
var mangledTypeName: TargetRelativeDirectPointer<CChar>
var fieldName: TargetRelativeDirectPointer<UInt8>
}
struct FiledRecordBuffer<Element>{
var element: Element
mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
return withUnsafePointer(to: &self) {
let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
return start
}
return UnsafeBufferPointer(start: ptr, count: n)
}
}
mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
}
}
}
4.1.7 解析Enum的數(shù)據(jù)
enum Week {
case Mon
case Tue
case Wed
case Thu
case Fri
case Sat
case Sun
}
// 按位轉(zhuǎn)換內(nèi)存指針
let ptr = unsafeBitCast(Week.self as Any.Type, to: UnsafeMutablePointer<TargetEnumMetadata>.self)
let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()
// 打印枚舉的名稱
print(String(cString: namePtr))
let field = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset()
for i in 0..<field.pointee.numFields {
let fieldRecord = field.pointee.fields.index(of: Int(i))
let fieldName = fieldRecord.pointee.fieldName.getApplyRelativeOffset()
// 打印枚舉元素值的名稱
print(String(cString: fieldName))
}
打印結(jié)果
4.2 Class 的實(shí)現(xiàn)
4.2.1 還原TargetClassMetadata
首先定位到源碼中的 Metadata.h
文件中项秉,找到 TargetClassMetadata
代碼如下
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
...
/// Swift-specific class flags.
ClassFlags Flags;
/// The address point of instances of this type.
uint32_t InstanceAddressPoint;
/// The required size of instances of this type.
/// 'InstanceAddressPoint' bytes go before the address point;
/// 'InstanceSize - InstanceAddressPoint' bytes go after it.
uint32_t InstanceSize;
/// The alignment mask of the address point of instances of this type.
uint16_t InstanceAlignMask;
/// Reserved for runtime use.
uint16_t Reserved;
/// The total size of the class object, including prefix and suffix
/// extents.
uint32_t ClassSize;
/// The offset of the address point within the class object.
uint32_t ClassAddressPoint;
// Description is by far the most likely field for a client to try
// to access directly, so we force access to go through accessors.
private:
/// An out-of-line Swift-specific description of the type, or null
/// if this is an artificial subclass. We currently provide no
/// supported mechanism for making a non-artificial subclass
/// dynamically.
TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
public:
/// A function for destroying instance variables, used to clean up after an
/// early return from a constructor. If null, no clean up will be performed
/// and all ivars must be trivial.
TargetSignedPointer<Runtime, ClassIVarDestroyer * __ptrauth_swift_heap_object_destructor> IVarDestroyer;
...
};
可以看到有 TargetClassMetadata
繼承自 TargetAnyClassMetadata
并且有 ClassFlags
類型的 Flags
屬性和 uint32_t
的 InstanceAddressPoint
绣溜、 InstanceSize
、 ClassSize
娄蔼、 ClassAddressPoint
屬性和 uint16_t
的 怖喻、 InstanceAlignMask
、 Reserved
屬性和 Description
岁诉、 IVarDestroyer
屬性锚沸。進(jìn)入到 TargetAnyClassMetadata
struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
...
// Note that ObjC classes do not have a metadata header.
/// The metadata for the superclass. This is null for the root class.
TargetSignedPointer<Runtime, const TargetClassMetadata<Runtime> *
__ptrauth_swift_objc_superclass>
Superclass;
#if SWIFT_OBJC_INTEROP
/// The cache data is used for certain dynamic lookups; it is owned
/// by the runtime and generally needs to interoperate with
/// Objective-C's use.
TargetPointer<Runtime, void> CacheData[2];
/// The data pointer is used for out-of-line metadata and is
/// generally opaque, except that the compiler sets the low bit in
/// order to indicate that this is a Swift metatype and therefore
/// that the type metadata header is present.
StoredSize Data;
...
};
發(fā)現(xiàn) TargetAnyClassMetadata
繼承自 TargetHeapMetadata
并且有三個(gè)屬性 Superclass
、 CacheData
唉侄、 Data
咒吐。跳轉(zhuǎn)到 TargetHeapMetadata
中
struct TargetHeapMetadata : TargetMetadata<Runtime> {
using HeaderType = TargetHeapMetadataHeader<Runtime>;
TargetHeapMetadata() = default;
constexpr TargetHeapMetadata(MetadataKind kind)
: TargetMetadata<Runtime>(kind) {}
#if SWIFT_OBJC_INTEROP
constexpr TargetHeapMetadata(TargetAnyClassMetadata<Runtime> *isa)
: TargetMetadata<Runtime>(isa) {}
#endif
};
沒有屬性并且繼承自 TargetMetadata
跳轉(zhuǎn)至 TargetMetadata
struct TargetMetadata {
...
/// The kind. Only valid for non-class metadata; getKind() must be used to get
/// the kind value.
StoredPointer Kind;
...
};
有一個(gè)屬性 Kind
, 根據(jù)以上源碼分析可以得出 TargetClassMetadata
的數(shù)據(jù)結(jié)構(gòu)
struct TargetClassMetadata{
var kind: Int
var superClass: Any.Type
var cacheData: (Int, Int)
var data: Int
var classFlags: Int32
var instanceAddressPoint: UInt32
var instanceSize: UInt32
var instanceAlignmentMask: UInt16
var reserved: UInt16
var classSize: UInt32
var classAddressPoint: UInt32
var typeDescriptor: UnsafeMutablePointer<Any>
var iVarDestroyer: UnsafeRawPointer
}
4.2.2 還原typeDescriptor
其中的 typeDescriptor
就是 class
的描述信息属划,回到源碼中的 TargetClassMetadata
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
...
/// An out-of-line Swift-specific description of the type, or null
/// if this is an artificial subclass. We currently provide no
/// supported mechanism for making a non-artificial subclass
/// dynamically.
TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
...
};
定位到 TargetClassDescriptor
class TargetClassDescriptor final
: public TargetTypeContextDescriptor<Runtime>,
public TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
TargetTypeGenericContextDescriptorHeader,
/*additional trailing objects:*/
TargetResilientSuperclass<Runtime>,
TargetForeignMetadataInitialization<Runtime>,
TargetSingletonMetadataInitialization<Runtime>,
TargetVTableDescriptorHeader<Runtime>,
TargetMethodDescriptor<Runtime>,
TargetOverrideTableHeader<Runtime>,
TargetMethodOverrideDescriptor<Runtime>,
TargetObjCResilientClassStubInfo<Runtime>,
TargetCanonicalSpecializedMetadatasListCount<Runtime>,
TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
...
/// The type of the superclass, expressed as a mangled type name that can
/// refer to the generic arguments of the subclass type.
TargetRelativeDirectPointer<Runtime, const char> SuperclassType;
union {
/// If this descriptor does not have a resilient superclass, this is the
/// negative size of metadata objects of this class (in words).
uint32_t MetadataNegativeSizeInWords;
/// If this descriptor has a resilient superclass, this is a reference
/// to a cache holding the metadata's extents.
TargetRelativeDirectPointer<Runtime,
TargetStoredClassMetadataBounds<Runtime>>
ResilientMetadataBounds;
};
union {
/// If this descriptor does not have a resilient superclass, this is the
/// positive size of metadata objects of this class (in words).
uint32_t MetadataPositiveSizeInWords;
/// Otherwise, these flags are used to do things like indicating
/// the presence of an Objective-C resilient class stub.
ExtraClassDescriptorFlags ExtraClassFlags;
};
/// The number of additional members added by this class to the class
/// metadata. This data is opaque by default to the runtime, other than
/// as exposed in other members; it's really just
/// NumImmediateMembers * sizeof(void*) bytes of data.
///
/// Whether those bytes are added before or after the address point
/// depends on areImmediateMembersNegative().
uint32_t NumImmediateMembers; // ABI: could be uint16_t?
StoredSize getImmediateMembersSize() const {
return StoredSize(NumImmediateMembers) * sizeof(StoredPointer);
}
/// Are the immediate members of the class metadata allocated at negative
/// offsets instead of positive?
bool areImmediateMembersNegative() const {
return getTypeContextDescriptorFlags().class_areImmediateMembersNegative();
}
/// The number of stored properties in the class, not including its
/// superclasses. If there is a field offset vector, this is its length.
uint32_t NumFields;
private:
/// The offset of the field offset vector for this class's stored
/// properties in its metadata, in words. 0 means there is no field offset
/// vector.
///
/// If this class has a resilient superclass, this offset is relative to
/// the size of the resilient superclass metadata. Otherwise, it is
/// absolute.
uint32_t FieldOffsetVectorOffset;
...
};
TargetClassDescriptor
繼承自 TargetTypeContextDescriptor
并且有 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
屬性缭付。根據(jù)在上面對(duì) Enum
數(shù)據(jù)結(jié)構(gòu)的分析和 TargetClassMetadata
的源碼分析柿估,最后得出 TargetClassMetadata
的最終數(shù)據(jù)結(jié)構(gòu)為
struct TargetClassDescriptor{
var flags: Int32
var parent: Int32
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
var superClassType: TargetRelativeDirectPointer<CChar>
var metadataNegativeSizeInWords: Int32
var metadataPositiveSizeInWords: Int32
var numImmediateMembers: Int32
var numFields: Int32
// 每一個(gè)屬性值距離當(dāng)前實(shí)例對(duì)象地址的偏移量
var fieldOffsetVectorOffset: Int32
func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int>{
return metadata.assumingMemoryBound(to: Int.self).advanced(by: numericCast(self.fieldOffsetVectorOffset))
}
var genericArgumentOffset: Int {
return 2
}
}
struct TargetClassMetadata{
var kind: Int
var superClass: Any.Type
var cacheData: (Int, Int)
var data: Int
var classFlags: Int32
var instanceAddressPoint: UInt32
var instanceSize: UInt32
var instanceAlignmentMask: UInt16
var reserved: UInt16
var classSize: UInt32
var classAddressPoint: UInt32
var typeDescriptor: UnsafeMutablePointer<TargetClassDescriptor>
var iVarDestroyer: UnsafeRawPointer
}
4.2.3 解析Class的數(shù)據(jù)
class Teacher {
var age: Int = 18
var name: String = "小明"
}
var t = Teacher()
let ptr = unsafeBitCast(Teacher.self as Any.Type, to: UnsafeMutablePointer<TargetClassMetadata>.self)
let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()
print("當(dāng)前類的名稱: \(String(cString: namePtr))")
let numFileds = ptr.pointee.typeDescriptor.pointee.numFields
print("當(dāng)前類屬性的個(gè)數(shù): \(numFileds)")
打印結(jié)果
再獲取屬性信息
// 獲取偏移量
let offsets = ptr.pointee.typeDescriptor.pointee.getFieldOffsets(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self))
for i in 0..<numFileds{
let fieldDespritor = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getApplyRelativeOffset()
print("fieldDespritor: \(String(cString: fieldDespritor))")
let fieldOffset = offsets[Int(i)]
let typeMangleName = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getApplyRelativeOffset()
// 獲取泛型參數(shù)
let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
// 標(biāo)準(zhǔn)C語言函數(shù)庫
let fieldType = swift_getTypeByMangledNameInContext(
typeMangleName,
256,
UnsafeRawPointer(ptr.pointee.typeDescriptor),
UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
// 將fieldType轉(zhuǎn)換成Any類型
let type = unsafeBitCast(fieldType, to: Any.Type.self)
// 獲取首地址
let instanceAddress = Unmanaged.passUnretained(t as AnyObject).toOpaque()
// 將屬性的類型信息綁定到協(xié)議的類型信息
let valueType = customCast(type: type)
// 獲取屬性值的地址的值
let valueValue = valueType.get(from: instanceAddress.advanced(by: fieldOffset))
print("fieldType:\(type) \nfieldValue:\(valueValue) ")
}
其中 swift_getTypeByMangledNameInContext
是調(diào)用的C語言的標(biāo)準(zhǔn)函數(shù)這里通過swift橋接的形式進(jìn)行
//typeNameStart 地址信息
//typeNameLength 名稱混寫長(zhǎng)度信息
//context 上下文
//genericArgs 泛型參數(shù)
const void * _Nullable swift_getTypeByMangledNameInContext(
const char * _Nullable typeNameStart,
int typeNameLength,
const void * _Nullable context,
const void * _Nullable const * _Nullable genericArgs);
customCast(type: type)
具體內(nèi)容為
protocol BrigeProtocol {}
extension BrigeProtocol {
// 屬性值的地址傳入進(jìn)來 后 返回屬性值
static func get(from pointer: UnsafeRawPointer) -> Any {
pointer.assumingMemoryBound(to: Self.self).pointee
}
}
// 協(xié)議的metadata
struct BrigeProtocolMetadata {
let type: Any.Type
let witness: Int
}
func customCast(type: Any.Type) -> BrigeProtocol.Type {
let container = BrigeProtocolMetadata(type: type, witness: 0)
let protocolType = BrigeProtocol.Type.self
// 按位強(qiáng)制轉(zhuǎn)換成protocolType
let cast = unsafeBitCast(container, to: protocolType)
return cast
}
打印結(jié)果
4.3 Struct 的實(shí)現(xiàn)
4.3.1 還原TargetStructMetadata
首先定位到源碼中的 Metadata.h
文件中,找到 TargetStructMetadata
代碼如下
struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
using StoredPointer = typename Runtime::StoredPointer;
using TargetValueMetadata<Runtime>::TargetValueMetadata;
const TargetStructDescriptor<Runtime> *getDescription() const {
return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
}
// The first trailing field of struct metadata is always the generic
// argument array.
/// Get a pointer to the field offset vector, if present, or null.
const uint32_t *getFieldOffsets() const {
auto offset = getDescription()->FieldOffsetVectorOffset;
if (offset == 0)
return nullptr;
auto asWords = reinterpret_cast<const void * const*>(this);
return reinterpret_cast<const uint32_t *>(asWords + offset);
}
bool isStaticallySpecializedGenericMetadata() const {
auto *description = getDescription();
if (!description->isGeneric())
return false;
auto *trailingFlags = getTrailingFlags();
if (trailingFlags == nullptr)
return false;
return trailingFlags->isStaticSpecialization();
}
bool isCanonicalStaticallySpecializedGenericMetadata() const {
auto *description = getDescription();
if (!description->isGeneric())
return false;
auto *trailingFlags = getTrailingFlags();
if (trailingFlags == nullptr)
return false;
return trailingFlags->isCanonicalStaticSpecialization();
}
const MetadataTrailingFlags *getTrailingFlags() const {
auto description = getDescription();
auto flags = description->getFullGenericContextHeader()
.DefaultInstantiationPattern->PatternFlags;
if (!flags.hasTrailingFlags())
return nullptr;
auto fieldOffset = description->FieldOffsetVectorOffset;
auto offset =
fieldOffset +
// Pad to the nearest pointer.
((description->NumFields * sizeof(uint32_t) + sizeof(void *) - 1) /
sizeof(void *));
auto asWords = reinterpret_cast<const void *const *>(this);
return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
}
static constexpr int32_t getGenericArgumentOffset() {
return sizeof(TargetStructMetadata<Runtime>) / sizeof(StoredPointer);
}
static bool classof(const TargetMetadata<Runtime> *metadata) {
return metadata->getKind() == MetadataKind::Struct;
}
};
我們發(fā)現(xiàn)TargetStructMetadata
和 TargetEnumMetadata
如出一轍都是繼承自 TargetValueMetadata陷猫,通過之前對(duì) TargetEnumMetadata
的分析不難得出 TargetStructMetadata
的結(jié)構(gòu)為
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;
...
};
發(fā)現(xiàn)跟 TargetEnumDescriptor
也差不太多都是繼承自 TargetValueTypeDescriptor
秫舌,只是屬性不一樣是 兩個(gè) uint32_t
類型的 NumFields
和 FieldOffsetVectorOffset
這兩個(gè)屬性在 TargetClassDescriptor
中有
所以最后能夠得到 TargetSructMetadata
的最終數(shù)據(jù)結(jié)構(gòu)為
struct TargetStructMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer<TargetStructDescriptor>
}
struct TargetStructDescriptor {
var flags: UInt32
var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
var numFields: Int32
// 每一個(gè)屬性值距離當(dāng)前實(shí)例對(duì)象地址的偏移量
var fieldOffsetVectorOffset: Int32
func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int32>{
return metadata.assumingMemoryBound(to: Int32.self).advanced(by: numericCast(self.fieldOffsetVectorOffset) * 2)
}
var genericArgumentOffset: Int {
return 2
}
}
4.3.2 解析Struct的數(shù)據(jù)
struct Person {
var age: Int = 18
var name: String = "小明"
}
var person = Person()
let ptr = unsafeBitCast(Person.self as Any.Type, to: UnsafeMutablePointer<TargetStructMetadata>.self)
let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()
print("當(dāng)前結(jié)構(gòu)體的名稱: \(String(cString: namePtr))")
let numFileds = ptr.pointee.typeDescriptor.pointee.numFields
print("當(dāng)前結(jié)構(gòu)體屬性的個(gè)數(shù): \(numFileds)")
// 獲取偏移量
let offsets = ptr.pointee.typeDescriptor.pointee.getFieldOffsets(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self))
for i in 0..<numFileds{
let fieldDespritor = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getApplyRelativeOffset()
print("fieldDespritor: \(String(cString: fieldDespritor))")
let fieldOffset = offsets[Int(i)]
let typeMangleName = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getApplyRelativeOffset()
// 獲取泛型參數(shù)
let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
// 標(biāo)準(zhǔn)C語言函數(shù)庫
let fieldType = swift_getTypeByMangledNameInContext(
typeMangleName,
256,
UnsafeRawPointer(ptr.pointee.typeDescriptor),
UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
// 將fieldType轉(zhuǎn)換成Any類型
let type = unsafeBitCast(fieldType, to: Any.Type.self)
// 獲取實(shí)例對(duì)象p的指針 需要轉(zhuǎn)換成UnsafeRawPointer 并且綁定成1字節(jié)即Int8類型的妖,
// 因?yàn)楹竺媸前醋止?jié)計(jì)算偏移量的,不轉(zhuǎn)換足陨,會(huì)以結(jié)構(gòu)體的長(zhǎng)度偏移
let instanceAddress = withUnsafePointer(to: &person){
return UnsafeRawPointer($0).assumingMemoryBound(to: Int8.self)
}
// 將屬性的類型信息綁定到協(xié)議的類型信息
let valueType = customCast(type: type)
// 獲取屬性值的地址的值
let valueValue = valueType.get(from: instanceAddress.advanced(by: Int(fieldOffset)))
print("fieldType:\(type) \nfieldValue:\(valueValue) ")
}
打印結(jié)果
自此通過對(duì)Mirror源碼的原理實(shí)現(xiàn)了對(duì) Enum
嫂粟、 Class
、 Struct
三種類型的解析小工具