swift-Mirror反射


struct GitArtOS {
    var age = 18
    var name = "FGH"
    var subclassName = "二年級"
    
}

struct GitArtOSMetadata {
    var kind:        Int
    var description: UnsafeMutablePointer<GitArtOSMetadataDesc>
}

struct GitArtOSMetadataDesc {
    var flags:              UInt32
    var parent:             UInt32  // 展示用Uint32代替,實際是相同大小的結構體,
    var name:               GitArtOSDirectPointer<CChar>
    // . . .  (當前研究獲取屬性類型,後面的屬性先不管)
    var accessFunctionPtr:       GitArtOSDirectPointer<UnsafeRawPointer>  // 不在乎具體類型,就先用UnsafeRawPointer
        var fields:                  GitArtOSDirectPointer<GitArtOSFieldDescription>  // 不在乎具體類型,就先用UnsafeRawPointer
        var numFields:               UInt32  // 屬性個數
        var fieldOffsetVectorOffset: UInt32
}

struct GitArtOSDirectPointer<T>{
    var offset: Int32
    
    // 偏移offset位置,獲取內容指針
    mutating func get() -> UnsafeMutablePointer<T> {
        let offset = self.offset
        // withUnsafePointer獲取指針
        return withUnsafePointer(to: &self) { p in
            // UnsafeMutablePointer 返回T類型對象的指針
            // UnsafeRawPointer將p指針轉換爲未知類型
            // numericCast將offset轉換爲偏移單位數
            // advanced進行內存偏移
            // assumingMemoryBound綁定指針爲T類型
            return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))
        }
        
    }
}


// 記錄結構體內所有屬性的結構
struct GitArtOSFieldDescription {
    var MangledTypeName:         GitArtOSDirectPointer<CChar>
    var Superclass:              GitArtOSDirectPointer<CChar>
    var Kind:                    UInt16
    var FieldRecordSize:         UInt16
    var NumFields:               UInt32
    var fgfields:                  GitArtOSFieldRecord // 連續存儲空間 (有幾個數據,就會在後面添加幾個記錄,通過內存平移讀取)
}

// 每個屬性的內容
struct GitArtOSFieldRecord {
    var flag:                    Int32
    var mangledTypeName:         GitArtOSDirectPointer<CChar>
    var fieldName:               GitArtOSDirectPointer<CChar>   // 屬性名稱
}


let gitartos = unsafeBitCast(GitArtOS.self as Any.Type, to:  UnsafeMutablePointer<GitArtOSMetadata>.self)
let namePtr = gitartos.pointee.description.pointee.name.get()
print(String(cString:namePtr ))
//GitArtOS
let count = gitartos.pointee.description.pointee.numFields
print("GitArtOS屬性個數:\(count)")


// 單獨讀取第一個屬性名
var fields = gitartos.pointee.description.pointee.fields.get()
let fieldRecord1Name = fields.pointee.fgfields.fieldName.get()
print(String(cString: fieldRecord1Name))

// 讀取所有記錄
print("----讀取所有屬性名----")
(0..<count).forEach { index in
    let recordPtr = withUnsafePointer(to: &fields.pointee.fgfields) {
        return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: GitArtOSFieldRecord.self).advanced(by: Int(index)))
    }
    print(String(cString: recordPtr.pointee.fieldName.get()))
}

print("--GitArtOS --dump----")
dump(GitArtOS()) // 相似的實現方式

打印結果:

GitArtOS
GitArtOS屬性個數:3
age
----讀取所有屬性名----
age
name
subclassName
--GitArtOS --dump----
▿ __lldb_expr_22.GitArtOS
  - age: 18
  - name: "FGH"
  - subclassName: "二年級"

Mirror 可以動態獲取類型成員變量,在運行時可以調用方法屬性等行爲的特性.

  1. Mirror.swift文件
  2. 初始化方法 public init(reflecting subject: Any) 和 獲取屬性個數_getChildCount
  3. 類型獲取 搜索_getNormalizedType:
  4. 分析結構: structMetadataRelativeDirectPointer
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章