上一節(jié)台诗,我們簡(jiǎn)單體驗(yàn)
了Mirror
反射機(jī)制香伴。
本節(jié)刃泡,通過(guò)源碼栅哀,深入探索Mirror反射
??
- 初始化
- 屬性類(lèi)型
- 屬性個(gè)數(shù)
- 屬性值
-
Mirror
(反射):
可以動(dòng)態(tài)
獲取類(lèi)型
、成員變量
究西,在運(yùn)行時(shí)
可以調(diào)用方法
货葬、屬性
等行為的特性
。
回顧
Mirror
的簡(jiǎn)單使用
:class HTPerson { var name = "ht" var age = 18 } let p = HTPerson() let mirror = Mirror(reflecting: p.self) for pro in mirror.children { print("\(pro.label ?? ""):\(pro.value)") }
- 打印結(jié)果:
1. 初始化
我們知道蘸炸,OC
中通過(guò)Runtime
能輕松獲取屬性
、方法
尖奔、協(xié)議
等搭儒,但swift
的Mirror
是如何獲取到屬性類(lèi)型
穷当、個(gè)數(shù)
、值
的呢淹禾?
-
帶著這些疑問(wèn)馁菜,我們?cè)?code>swift源碼中搜索
Mirror.swift
:
-
我們
搜索
并找到
初始化方法public init(reflecting subject: Any)
,從這里開(kāi)始我們的探索:
首先,我們分析一下如何通過(guò)
subject
來(lái)獲取類(lèi)型
铃岔。
2. 類(lèi)型獲取
- 搜索
_getNormalizedType
:
注意:
源碼分析
時(shí)汪疮,首先
分析結(jié)構(gòu)
,結(jié)構(gòu)是由繼承鏈
上的所有屬性
共同決定的毁习。而
函數(shù)
只是為
所有屬性服務(wù)
的智嚷。所以我們的重心
,就是先找到結(jié)構(gòu)
纺且,嘗試重寫(xiě)結(jié)構(gòu)
盏道,能使用自己的結(jié)構(gòu)完整讀取
到相應(yīng)的內(nèi)容
,證明
源碼分析
的結(jié)果是正確
的隆檀。在這個(gè)過(guò)程摇天,
順道
看一眼函數(shù)
粹湃,在屬性操作
時(shí)恐仑,回頭分析
哪些函數(shù)
操作了它,是如何實(shí)現(xiàn)
的为鳄。
這樣才能完整
的梳理清楚
裳仆。(當(dāng)然,得花大量時(shí)間反復(fù)研究才行)
- 根據(jù)
源碼探索
孤钦,以struct類(lèi)型
為例歧斟,可知structMetaData
結(jié)構(gòu)為:
- 按照
structMetadata
格式,嘗試讀取struct
的類(lèi)型:
(get
:仿照源碼中RelativeDirectPointer (相對(duì)位置指針)
進(jìn)行偏移
偏形,獲取真實(shí)內(nèi)存值
)
struct StructMetadata {
var kind: Int
var description: UnsafeMutablePointer<StructMetadataDesc>
}
struct StructMetadataDesc {
var flags: UInt32
var parent: UInt32 // 展示用Uint32代替静袖,實(shí)際是相同大小的結(jié)構(gòu)體,
var name: RelativeDirectPointer<CChar>
// . . . (當(dāng)前研究獲取屬性類(lèi)型俊扭,后面的屬性先不管)
}
struct RelativeDirectPointer<T>{
var offset: Int32
// 偏移offset位置队橙,獲取內(nèi)容指針
mutating func get() -> UnsafeMutablePointer<T> {
let offset = self.offset
// withUnsafePointer獲取指針
return withUnsafePointer(to: &self) { p in
// UnsafeMutablePointer 返回T類(lèi)型對(duì)象的指針
// UnsafeRawPointer將p指針轉(zhuǎn)換為未知類(lèi)型
// numericCast將offset轉(zhuǎn)換為偏移單位數(shù)
// advanced進(jìn)行內(nèi)存偏移
// assumingMemoryBound綁定指針為T(mén)類(lèi)型
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))
}
}
}
struct HTStruct {
var age = 18
}
// 讀取將HTStuct指針內(nèi)容,賦值給StructMetadata (unsafeBitCast: 通過(guò)字節(jié)讀取)
let p = unsafeBitCast(HTStruct.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)
// 讀取當(dāng)前name的內(nèi)容指針
let namePtr = p.pointee.description.pointee.name.get()
// name是CChar類(lèi)型萨惑,轉(zhuǎn)為字符串輸出
print(String(cString: namePtr))
- 成功獲取
HTStruct
類(lèi)型:
3. 屬性個(gè)數(shù)
-
回到
初始化方法
,可以看到是通過(guò)_getChildCount
獲取屬性個(gè)數(shù):
仿寫(xiě)代碼捐康,
struct StructMetadata {
var kind: Int
var description: UnsafeMutablePointer<StructMetadataDesc>
}
struct StructMetadataDesc {
var flags: UInt32
var parent: UInt32 // 展示用Uint32代替,實(shí)際是相同大小的結(jié)構(gòu)體庸蔼,
var name: RelativeDirectPointer<CChar> // 不在乎具體類(lèi)型解总,就先用UnsafeRawPointer
var accessFunctionPtr: RelativeDirectPointer<UnsafeRawPointer> // 不在乎具體類(lèi)型,就先用UnsafeRawPointer
var fields: RelativeDirectPointer<UnsafeRawPointer> // 不在乎具體類(lèi)型姐仅,就先用UnsafeRawPointer
var numFields: UInt32 // 屬性個(gè)數(shù)
var fieldOffsetVectorOffset: UInt32
}
struct RelativeDirectPointer<T>{
var offset: Int32
// 偏移offset位置花枫,獲取內(nèi)容指針
mutating func get() -> UnsafeMutablePointer<T> {
let offset = self.offset
// withUnsafePointer獲取指針
return withUnsafePointer(to: &self) { p in
// UnsafeMutablePointer 返回T類(lèi)型對(duì)象的指針
// UnsafeRawPointer將p指針轉(zhuǎn)換為未知類(lèi)型
// numericCast將offset轉(zhuǎn)換為偏移單位數(shù)
// advanced進(jìn)行內(nèi)存偏移
// assumingMemoryBound綁定指針為T(mén)類(lèi)型
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))
}
}
}
struct HTStruct {
var age = 18
}
// 讀取將HTStuct指針內(nèi)容刻盐,賦值給StructMetadata (unsafeBitCast: 通過(guò)字節(jié)讀取)
let p = unsafeBitCast(HTStruct.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)
// 讀取當(dāng)前name的內(nèi)容指針
let namePtr = p.pointee.description.pointee.name.get()
let count = p.pointee.description.pointee.numFields
// name是CChar類(lèi)型,轉(zhuǎn)為字符串輸出
print(String(cString: namePtr))
print("HTStruct屬性個(gè)數(shù):\(count)")
-
打印結(jié)果:
-
修改
結(jié)構(gòu)體屬性個(gè)數(shù)
后:
成功的重寫(xiě)結(jié)構(gòu)
劳翰,拿到屬性個(gè)數(shù)
隙疚,下面,我們來(lái)分析屬性值
的獲取
4. 屬性值
- 屬性值的獲取磕道,也是在
children
獲取時(shí)得到供屉。我們循著路徑,找到對(duì)應(yīng)類(lèi)型的impl
溺蕉,讀取description
里面的fields
伶丐,分析fields
內(nèi)部結(jié)構(gòu),發(fā)現(xiàn)每個(gè)屬性
是以FieldRecord
格式進(jìn)行存儲(chǔ)疯特。 存放的位置在fields
的最后哗魂。有幾個(gè)屬性
就會(huì)新增幾條FieldRecord
記錄,可通過(guò)內(nèi)存地址偏移
獲取所有屬性名
漓雅。
// 結(jié)構(gòu)體類(lèi)型
struct StructMetadata {
var kind: Int
var description: UnsafeMutablePointer<StructMetadataDesc>
}
// 結(jié)構(gòu)體類(lèi)型的描述
struct StructMetadataDesc {
var flags: UInt32
var parent: UInt32 // 展示用Uint32代替录别,實(shí)際是相同大小的結(jié)構(gòu)體,
var name: RelativeDirectPointer<CChar> // 不在乎具體類(lèi)型邻吞,就先用UnsafeRawPointer
var accessFunctionPtr: RelativeDirectPointer<UnsafeRawPointer> // 不在乎具體類(lèi)型组题,就先用UnsafeRawPointer
var fields: RelativeDirectPointer<FieldDescription> // 記錄所有屬性內(nèi)容
var numFields: UInt32 // 屬性個(gè)數(shù)
var fieldOffsetVectorOffset: UInt32
}
// 記錄結(jié)構(gòu)體內(nèi)所有屬性的結(jié)構(gòu)
struct FieldDescription {
var MangledTypeName: RelativeDirectPointer<CChar>
var Superclass: RelativeDirectPointer<CChar>
var Kind: UInt16
var FieldRecordSize: UInt16
var NumFields: UInt32
var fields: FieldRecord // 連續(xù)存儲(chǔ)空間 (有幾個(gè)數(shù)據(jù),就會(huì)在后面添加幾個(gè)記錄抱冷,通過(guò)內(nèi)存平移讀取)
}
// 每個(gè)屬性的內(nèi)容
struct FieldRecord {
var flag: Int32
var mangledTypeName: RelativeDirectPointer<CChar>
var fieldName: RelativeDirectPointer<CChar> // 屬性名稱(chēng)
}
// 相對(duì)位移指針
struct RelativeDirectPointer<T>{
var offset: Int32
// 偏移offset位置崔列,獲取內(nèi)容指針
mutating func get() -> UnsafeMutablePointer<T> {
let offset = self.offset
// withUnsafePointer獲取指針
return withUnsafePointer(to: &self) { p in
// UnsafeMutablePointer 返回T類(lèi)型對(duì)象的指針
// UnsafeRawPointer將p指針轉(zhuǎn)換為未知類(lèi)型
// numericCast將offset轉(zhuǎn)換為偏移單位數(shù)
// advanced進(jìn)行內(nèi)存偏移
// assumingMemoryBound綁定指針為T(mén)類(lèi)型
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))
}
}
}
struct HTStruct {
var age = 18
var name = "ht"
}
// 讀取將HTStuct指針內(nèi)容,賦值給StructMetadata (unsafeBitCast: 通過(guò)字節(jié)讀取)
let p = unsafeBitCast(HTStruct.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)
// 讀取當(dāng)前name的內(nèi)容指針
let namePtr = p.pointee.description.pointee.name.get()
let count = p.pointee.description.pointee.numFields
print("類(lèi)型:\(String(cString: namePtr))") // name是CChar類(lèi)型旺遮,轉(zhuǎn)為字符串輸出
print("屬性個(gè)數(shù):\(count)")
// 單獨(dú)讀取第一個(gè)屬性名
var fields = p.pointee.description.pointee.fields.get()
let fieldRecord1Name = fields.pointee.fields.fieldName.get()
print(String(cString: fieldRecord1Name))
// 讀取所有記錄
print("----讀取所有屬性名----")
(0..<count).forEach { index in
let recordPtr = withUnsafePointer(to: &fields.pointee.fields) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: FieldRecord.self).advanced(by: Int(index)))
}
print(String(cString: recordPtr.pointee.fieldName.get()))
}
print("----dump----")
dump(HTStruct()) // 相似的實(shí)現(xiàn)方式
本文從
struct結(jié)構(gòu)
開(kāi)始入手分析赵讯,通過(guò)源碼。從初始化
方法開(kāi)始耿眉,找到屬性類(lèi)型
边翼、屬性個(gè)數(shù)
、屬性值
鸣剪。成功還原
相應(yīng)數(shù)據(jù)格式
组底。初步窺探Mirror
的內(nèi)部實(shí)現(xiàn)。源碼的世界
西傀,都是大師級(jí)制作
斤寇。每次拜讀和分析,都能學(xué)
到一些思維方式
拥褂。本文僅僅作為一個(gè)引路篇
娘锁,更多有意思的東西,還需要我們自己慢慢探索饺鹃。