
一、Mirror的基本用法
所謂反射就是可以動(dòng)態(tài)獲取類型、成員信息,在運(yùn)?時(shí)可以調(diào)??法、屬性等?為的特性。在使?OC開發(fā)時(shí)很少?gòu)?qiáng)調(diào)其反射概念,因?yàn)镺C的Runtime要?其他語(yǔ)?中的反射強(qiáng)?的多。但是 Swift 是??類型安全的語(yǔ)?,不?持我們像 OC 那樣直接操作,它的標(biāo)準(zhǔn)庫(kù)仍然提供了反射機(jī)制來(lái)讓我們?cè)L問成員信息。
Swift 的反射機(jī)制是基于?個(gè)叫 Mirror 的結(jié)構(gòu)體來(lái)實(shí)現(xiàn)的。為具體的實(shí)例創(chuàng)建?個(gè)Mirror對(duì)象,然后就可以通過(guò)它查詢這個(gè)實(shí)例。
class ZGTeacher {
var age: Int = 18
func teach() {
print("teach")
}
}
///?先通過(guò)構(gòu)造?法構(gòu)建?個(gè)Mirror實(shí)例,這?傳?的參數(shù)是 Any,也就意味著當(dāng)前可以是類,結(jié) 構(gòu)體,枚舉等
let mirror = Mirror(reflecting: ZGTeacher())
///接下來(lái)遍歷 children 屬性,這是?個(gè)集合
for child in mirror.children {
///然后我們可以直接通過(guò) label 輸出當(dāng)前的名稱,value 輸出當(dāng)前反射的值
print("\(String(describing: child.label)):\(child.value)")
}
lldb打印
Optional("age"):18
實(shí)際使用案例
class ZGTeacher {
var age: Int = 18
func teach() {
print("teach")
}
}
func test(_ mirrorObj: Any) -> Any {
let mirror = Mirror(reflecting: mirrorObj)
guard !mirror.children.isEmpty else { return mirrorObj }
var result: [String : Any] = [ : ]
for child in mirror.children {
if let key = child.label {
result[key] = test(child.value)
} else {
print("No Keys")
}
}
return result
}
var reslut = test(ZGTeacher())
print(reslut)
我們想讓我們的函數(shù)不管是結(jié)構(gòu)體,類還是枚舉還是基礎(chǔ)類型也好,都能夠具備這個(gè)?法。這個(gè)時(shí)候我們是不是就可以?協(xié)議來(lái)做?什么意思那?
首先,我們定義一個(gè)協(xié)議,這里就表示如果想要具備模型轉(zhuǎn)字典的方式,那么這里就要遵循這個(gè)協(xié)議,然后實(shí)現(xiàn)jsonMap的方法。
protocol ZGJsonMap {
func jsonMap() -> Any
}
但是大家想一下,這個(gè)test方法里面的功能是不是通用的啊,也就意味著我們不需要每一個(gè)遵循了ZGJsonMap協(xié)議的都自己實(shí)現(xiàn),所以這里我們是不是說(shuō)可以給這個(gè)協(xié)議一個(gè)默認(rèn)的實(shí)現(xiàn)啊。
class ZGTeacher {
var age: Int = 18
func teach() {
print("teach")
}
}
enum JSONMapError: Error {
case emptyKey
case notConformProtocol
}
protocol JSONMap {
func jsonMap() throws -> Any
}
extension JSONMap {
func jsonMap() throws -> Any {
let mirror = Mirror(reflecting: self)
guard !mirror.children.isEmpty else { return self }
var result: [String : Any] = [:]
for child in mirror.children {
if let value = child.value as? JSONMap {
if let key = child.label {
result[key] = try? value.jsonMap()
} else {
return JSONMapError.emptyKey
}
} else {
return JSONMapError.notConformProtocol
}
}
return result
}
}
///我們需要對(duì)當(dāng)前的常見類型和自定義類型遵循JSONMap的協(xié)議
///這樣對(duì)于沒有value才能嵌套解析
extension ZGTeacher: JSONMap{}
extension Int: JSONMap{}
extension String: JSONMap{}
var t = ZGTeacher()
var t1 = try? t.jsonMap()
print(t1!)
二、Mirror源碼解析
?先我們先在源?件??搜索 Mirror.Swift ,在源碼中我們可以很清晰的看到 Mirror 是由結(jié)構(gòu)體實(shí)現(xiàn)的,我們忽略掉?些細(xì)節(jié),快速定位到初始化的?法。
public init(reflecting subject: Any) {
if case let customized as CustomReflectable = subject {
self = customized.customMirror
} else {
self = Mirror(internalReflecting: subject)
}
}
可以看到,這?接受?個(gè) Any 類型的參數(shù),同樣的這?有?個(gè) if case 的寫法來(lái)判斷當(dāng)前的 subject 是否遵循了customReflectable 協(xié)議,如果是我們就直接調(diào)? customMirror , 否則就進(jìn)?下級(jí)函數(shù)的調(diào)?。
這?有兩個(gè)需要注意的點(diǎn): if case 的寫法,這?其實(shí)枚舉 case 的模式匹配,和我們的 Switch ?樣,這?是只有?個(gè) case 的 switch 語(yǔ)句。與此同時(shí)這?出現(xiàn)了?個(gè) customRefletable 的協(xié)議。
這?我們看?下具體?法: ?先我們遵循 customReflectable協(xié)議,并實(shí)現(xiàn)其中的屬性 customMirror ; customMirror會(huì)返回?個(gè) Mirror 對(duì)象。代碼展示如下:
class ZGTeacher: 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
}
}
var t = ZGTeacher(age: 18, name: "zhang")
print("end")
實(shí)現(xiàn)這個(gè) CustomReflectable 最直觀的區(qū)別在于我們?cè)?lldb debug 中會(huì)出現(xiàn)更詳細(xì)的 debug 信息。
po t
? <ZGTeacher: 0x1007405a0>
- age : 18
- name : "zhang"
回到我們的源碼當(dāng)中,對(duì)字符串 Mirror(internalReflecting 在源碼當(dāng)中進(jìn)?檢索,我們 就能夠快速定位到 ReflectionMirror.swift ?件
extension Mirror {
internal init(internalReflecting subject: Any,
subjectType: Any.Type? = nil,
customAncestor: Mirror? = nil)
{
///subject:類型信息
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
在當(dāng)前文件中搜索getNormalizedType
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
這?使?了?個(gè)編譯器字段 @_silgen_name ,其實(shí)是Swift的?個(gè)隱藏符號(hào),作?是將某個(gè)C/C++語(yǔ)?函數(shù)直接映射為Swift函數(shù)。
什么意思那?我們的 Swift 是可以和C語(yǔ)?進(jìn)?交互的,?如我們?cè)贑中定義?個(gè)函數(shù):
int zg_add(int a, int b) {
return a + b;
}
接下來(lái)如果我們的 Swift 想要使?這個(gè)函數(shù),我們要怎么做??先要在 .h 頭?件中暴露這個(gè)函數(shù):

然后在當(dāng)前的橋接頭?件當(dāng)中暴露

這樣我們就能在swift里直接使用了。

是不是?較麻煩,這?我們把頭?件全部都刪掉:
@_silgen_name("zg_add")
func swift_zg_add(a: Int32, b: Int32) -> Int32
var value = swift_zg_add(a: 10, b: 20)
print(value)
這里一樣可以正常調(diào)用,是不是很簡(jiǎn)潔方便哪?
回到我們的源代碼,搜索getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type 最終調(diào)?的是 ReflectionMirror.cpp 中的 C++ 代碼。
// 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; });
}
我們往上翻?翻就能夠找到 call 函數(shù)的實(shí)現(xiàn),這?其實(shí)是?個(gè)回調(diào)函數(shù),當(dāng)前回調(diào)的具體數(shù)據(jù)都是由 ReflectionMirrorImpl 結(jié)構(gòu)體實(shí)現(xiàn)。
auto call = [&](ReflectionMirrorImpl *impl) {
impl->type = type;
impl->value = value;
auto result = f(impl);
return result;
};
ReflectionMirrorImpl 結(jié)構(gòu)體的具體實(shí)現(xiàn)(可以看到這是?個(gè)抽象類,也就意味著不同類型的反射都需要去實(shí)現(xiàn) ReflectionMirrorImpl ),這?我們?cè)谙?的代碼中也能看到 class, struct, enum, Tuple的具體實(shí)現(xiàn)。
truct 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() {}
};
這?我們?先以 struct 為例來(lái)看?下 Mirror 都是如何獲取到這些數(shù)據(jù)的。
當(dāng)前的屬性數(shù)量 (可以看到的是,這?通過(guò) Metadata 中的 getDescription查詢字段 NumFields )
intptr_t count() override {
if (!isReflectable()) {
return 0;
}
auto *Struct = static_cast<const StructMetadata *>(type);
return Struct->getDescription()->NumFields;
}
其中 getDescription()
const TargetStructDescriptor<Runtime> *getDescription() const {
return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
}
又?如具體屬性的獲取
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
unsigned tag;
const Metadata *payloadType;
bool indirect;
auto *caseName = getInfo(&tag, &payloadType, &indirect);
// Copy the enum itself so that we can project the data without destroying
// the original.
Any enumCopy;
auto *enumCopyContainer
= type->allocateBoxForExistentialIn(&enumCopy.Buffer);
type->vw_initializeWithCopy(enumCopyContainer,
const_cast<OpaqueValue *>(value));
// Copy the enum payload into a box
const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType);
BoxPair pair = swift_allocBox(boxType);
type->vw_destructiveProjectEnumData(enumCopyContainer);
boxType->vw_initializeWithTake(pair.buffer, enumCopyContainer);
type->deallocateBoxForExistentialIn(&enumCopy.Buffer);
value = pair.buffer;
// If the payload is indirect, we need to jump through the box to get it.
if (indirect) {
const HeapObject *owner = *reinterpret_cast<HeapObject * const *>(value);
value = swift_projectBox(const_cast<HeapObject *>(owner));
}
*outName = caseName;
*outFreeFunc = nullptr;
Any result;
result.Type = payloadType;
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(value));
swift_release(pair.object);
return AnyReturn(result);
}
可以看到是這?通篇都是通過(guò) Metadata , getDescription() , FieldDescrition 這?個(gè)東?來(lái)去實(shí)現(xiàn)的,?個(gè)是當(dāng)前類型的元數(shù)據(jù),?個(gè)是當(dāng)前類型的描述,?個(gè)是對(duì)當(dāng)前類型屬性的描述。所以看到這?我們能夠明? Mirror 是如何?作的。
同時(shí)我們?cè)谇?的探索過(guò)程中也探索了類,結(jié)構(gòu)體和枚舉,接下來(lái)我們嘗試能不能??利? Metadata 來(lái)還原獲取當(dāng)前類型的各種屬性。
三、StructMetadata源碼分析
3.1 TargetStructMetadata
- 首先我們搜索
TargetStructMetadata,找到TargetStructMetadata的定義
template <typename Runtime>
struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
/// 此處會(huì)返回一個(gè)TargetStructDescriptor類型的Description
const TargetStructDescriptor<Runtime> *getDescription() const {
return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
}
};

可以看出
TargetStructMetadata繼承自TargetValueMetadata
- 搜索
TargetValueMetadata,找到TargetValueMetadata的定義
struct TargetValueMetadata : public TargetMetadata<Runtime> {
TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> *
__ptrauth_swift_type_descriptor> Description;
};

我們只看到有一個(gè)
Description屬性,它的類型是TargetValueTypeDescriptor。TargetValueMetadata 繼承自TargetMetadata
- 搜索
TargetMetadata,找到TargetMetadata的定義
struct TargetMetadata {
private:
/// The kind. Only valid for non-class metadata; getKind() must be used to get
/// the kind value.
StoredPointer Kind;
};

我們只看到它有一個(gè)
Kind屬性。
3.2 TargetValueTypeDescriptor
- 首先我們根據(jù)
TargetStructMetadata,找到TargetStructMetadata定義中的TargetStructDescriptor,點(diǎn)擊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>> {
public:
uint32_t NumFields;
uint32_t FieldOffsetVectorOffset;
};


我們可以發(fā)現(xiàn)
TargetStructDescriptor有兩個(gè)屬性,分別是NumFields和FieldOffsetVectorOffset。NumFields主要表示結(jié)構(gòu)體中屬性的個(gè)數(shù),如果只有一個(gè)字段偏移量則表示偏移量的長(zhǎng)度。FieldOffsetVectorOffset表示這個(gè)結(jié)構(gòu)體元數(shù)據(jù)中存儲(chǔ)的屬性的字段偏移向量的偏移量,如果是0則表示沒有。TargetStructDescriptor 繼承自 TargetValueTypeDescriptor
- 點(diǎn)擊
TargetValueTypeDescriptor,找到TargetValueTypeDescriptor的定義
class TargetValueTypeDescriptor
: public TargetTypeContextDescriptor<Runtime> {
public:
static bool classof(const TargetContextDescriptor<Runtime> *cd) {
return cd->getKind() == ContextDescriptorKind::Struct ||
cd->getKind() == ContextDescriptorKind::Enum;
}
};

我們并沒有找到太多有用的信息,那么我們繼續(xù)向父類尋找。
- 點(diǎn)擊
TargetTypeContextDescriptor,找到TargetTypeContextDescriptor的定義
class TargetTypeContextDescriptor
: public TargetContextDescriptor<Runtime> {
public:
TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;
TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
/*Nullable*/ true> AccessFunctionPtr;
TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
/*nullable*/ true> Fields;
};

我們發(fā)現(xiàn)
TargetTypeContextDescriptor有Name、AccessFunctionPtr、Fields三個(gè)屬性:Name就是類型的名稱AccessFunctionPtr是該類型元數(shù)據(jù)訪問函數(shù)的指針Fields 是一個(gè)指向該類型的字段描述符的指針接下來(lái)我們?cè)倏纯?strong>
TargetTypeContextDescriptor的父類中還有什么有用的信息
- 點(diǎn)擊
TargetContextDescriptor,找到TargetContextDescriptor的定義
struct TargetContextDescriptor {
ContextDescriptorFlags Flags;
TargetRelativeContextPointer<Runtime> Parent;
};

這里我們可以看到:
1、這就是
descriptor的基類2、有兩個(gè)屬性,分別是
Flags和Parent3、
Flags是描述上下文的標(biāo)志,包括它的種類和格式版本。4、
Parent是記錄父類上下文的,如果是頂級(jí)則為null。
3.3 Description中的屬性
-
Flags
Flags.png
從截圖的源碼中我們可以看到這個(gè)FLags實(shí)際是個(gè)uint32_t的值,按位存儲(chǔ)著kind、isGeneric、isUnique、version、kindSpecificFlags等信息。 -
Parent
Parent的類型是TargetRelativeContextPointer<Runtime>,我們來(lái)看一下TargetRelativeContextPointer,點(diǎn)擊跳轉(zhuǎn)過(guò)去:
TargetRelativeContextPointer.png
我們可以看到TargetRelativeContextPointer是取自RelativeIndirectablePointer的別名,繼續(xù)點(diǎn)擊進(jìn)行查看:
RelativeIndirectablePointer.png
根據(jù)注釋知道這個(gè)類的主要作用是存儲(chǔ)在內(nèi)存中的對(duì)象的相對(duì)引用。通過(guò)RelativeOffsetPlusIndirect屬性存儲(chǔ)相對(duì)的地址偏移量。
再通過(guò)get()函數(shù)獲取,在get()函數(shù)中,會(huì)調(diào)用applyRelativeOffset函數(shù),進(jìn)行地址的偏移。applyRelativeOffset.png

最后返回的時(shí)候我們可以看到
base + extendOffset,基地址加上偏移的值,最后得到真實(shí)的地址。
- Fields
TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
/*nullable*/ true> Fields;
這里看看FieldDescriptor點(diǎn)擊跳轉(zhuǎn)到其源碼處,部分源碼如下:
class FieldDescriptor {
const FieldRecord *getFieldRecordBuffer() const {
return reinterpret_cast<const FieldRecord *>(this + 1);
}
public:
const RelativeDirectPointer<const char> MangledTypeName;
const RelativeDirectPointer<const char> Superclass;
const FieldDescriptorKind Kind;
const uint16_t FieldRecordSize;
const uint32_t NumFields;
};
這里有5個(gè)屬性:
1、MangledTypeName
2、Superclass
3、kind
4、FieldRecordSize
5、NumFields
關(guān)于getFieldRecordBuffer函數(shù)的返回值FieldRecord源碼如下:

FieldRecord主要是封裝了一些屬性,用于存儲(chǔ)這些值。
3.4 type
我們來(lái)看一下type是怎么取的:
調(diào)用swift_reflectionMirror_normalizedType函數(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; });
}
比如說(shuō)這是個(gè)結(jié)構(gòu)體,此時(shí)的impl就是個(gè)StructImpl類型,所以這里的type是StructImpl父類ReflectionMirrorImpl的屬性type。
3.5 count
調(diào)用swift_reflectionMirror_count函數(shù)
// func _getChildCount<T>(_: T, type: Any.Type) -> Int
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
intptr_t swift_reflectionMirror_count(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) {
return impl->count();
});
}
同樣還以結(jié)構(gòu)體為例,此時(shí)的impl為StructImpl,內(nèi)部的count()函數(shù):

這里的
Struct就是個(gè)TargetStructMetadata類型,通過(guò)getDescription()函數(shù)獲取到一個(gè)TargetStructDescriptor類型的Description,然后取NumFields**的值就是我們要的**count`。
3.6 屬性名和屬性值
我們知道在Mirror中通過(guò)其初始化方法返回一個(gè)提供該值子元素的AnyCollection<Child>類型的children集合,children是一個(gè)元組(label: String?, value: Any),label是一個(gè)可選類型的屬性名,value是屬性值。

在分析
internalReflecting函數(shù)的時(shí)候,我們說(shuō)children是懶加載的,而加載的時(shí)候會(huì)調(diào)用getChild方法,getChild方法源碼入下:
在
getChild方法中還會(huì)調(diào)用_getChild方法,源碼如下:
_getChild方法同樣是使用@_silgen_name修飾符最終調(diào)用的C++中的swift_reflectionMirror_subscript函數(shù)。
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
AnyReturn swift_reflectionMirror_subscript(OpaqueValue *value, const Metadata *type,
intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *),
const Metadata *T) {
return call(value, T, type, [&](ReflectionMirrorImpl *impl) {
return impl->subscript(index, outName, outFreeFunc);
});
}
這里我們可以看到是調(diào)用了impl的subscript函數(shù),同樣以結(jié)構(gòu)體為例,我們?cè)?strong>StructImpl中找到該函數(shù),源碼如下:

通過(guò)
subscript函數(shù)我們可以看到這里面還會(huì)調(diào)用childMetadata獲取到fieldInfo,其實(shí)這里就是獲取type,也就是屬性名,通過(guò)childOffset函數(shù)和index獲取到對(duì)應(yīng)的偏移量,最后根據(jù)內(nèi)存偏移取到屬性值。childMetadata核心點(diǎn)是調(diào)用getFieldAt函數(shù)獲取屬性名稱。
getFieldAt(const Metadata *base, unsigned index) {
using namespace reflection;
// If we failed to find the field descriptor metadata for the type, fall
// back to returning an empty tuple as a standin.
auto failedToFindMetadata = [&]() -> std::pair<StringRef, FieldType> {
auto typeName = swift_getTypeName(base, /*qualified*/ true);
missing_reflection_metadata_warning(
"warning: the Swift runtime found no field metadata for "
"type '%*s' that claims to be reflectable. Its fields will show up as "
"'unknown' in Mirrors\n",
(int)typeName.length, typeName.data);
return {"unknown", FieldType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))};
};
auto *baseDesc = base->getTypeContextDescriptor();
if (!baseDesc)
return failedToFindMetadata();
auto *fields = baseDesc->Fields.get();
if (!fields)
return failedToFindMetadata();
auto &field = fields->getFields()[index];
// Bounds are always valid as the offset is constant.
auto name = field.getFieldName();
// Enum cases don't always have types.
if (!field.hasMangledTypeName())
return {name, FieldType::untypedEnumCase(field.isIndirectCase())};
auto typeName = field.getMangledTypeName();
SubstGenericParametersFromMetadata substitutions(base);
auto result = swift_getTypeByMangledName(
MetadataState::Complete, typeName, substitutions.getGenericArgs(),
[&substitutions](unsigned depth, unsigned index) {
return substitutions.getMetadata(depth, index);
},
[&substitutions](const Metadata *type, unsigned index) {
return substitutions.getWitnessTable(type, index);
});
// If demangling the type failed, pretend it's an empty type instead with
// a log message.
TypeInfo typeInfo;
if (result.isError()) {
typeInfo = TypeInfo({&METADATA_SYM(EMPTY_TUPLE_MANGLING),
MetadataState::Complete}, {});
auto *error = result.getError();
char *str = error->copyErrorString();
missing_reflection_metadata_warning(
"warning: the Swift runtime was unable to demangle the type "
"of field '%*s'. the mangled type name is '%*s': %s. this field will "
"show up as an empty tuple in Mirrors\n",
(int)name.size(), name.data(), (int)typeName.size(), typeName.data(),
str);
error->freeErrorString(str);
} else {
typeInfo = result.getType();
}
auto fieldType = FieldType(typeInfo.getMetadata());
fieldType.setIndirect(field.isIndirectCase());
fieldType.setReferenceOwnership(typeInfo.getReferenceOwnership());
fieldType.setIsVar(field.isVar());
return {name, fieldType};
}
我們可以看到在上面這個(gè)方法中:
- 首先通過(guò)
getTypeContextDescriptor獲取baseDesc,也就是我們說(shuō)的Description - 然后通過(guò)
Fields.get()獲取到fields - 接著通過(guò)
getFields()[index]獲取對(duì)應(yīng)的field - 最后通過(guò)
getFieldName()函數(shù)獲取到屬性名稱 -
getTypeContextDescriptor函數(shù)在struct TargetMetadata中,通過(guò)這個(gè)函數(shù)獲取到一個(gè)TargetStructDescriptor,它的父類的父類TargetTypeContextDescriptor中的Fields屬性 -
Fields屬性的類型TargetRelativeDirectPointer中有get方法 - 實(shí)際中使用的
FieldDescriptor類中getFieldRecordBuffer方法返回的FieldRecord中的getFieldName函數(shù)
getFields 源碼:
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};
}
關(guān)于getFields我們可以看到這是一塊連續(xù)的空間,在begin和end中:
-
begin就是getFieldRecordBuffer -
getFieldRecordBuffer就是Begin + NumFields - 所以這就是一塊連續(xù)內(nèi)存的訪問
childOffset 源碼:
分析完了屬性名的獲取,我們來(lái)看看偏移量的獲取。
intptr_t childOffset(intptr_t i) override {
auto *Clas = static_cast<const ClassMetadata*>(type);
auto description = Clas->getDescription();
if (i < 0 || (size_t)i > description->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
// FIXME: If the class has ObjC heritage, get the field offset using the ObjC
// metadata, because we don't update the field offsets in the face of
// resilient base classes.
uintptr_t fieldOffset;
if (usesNativeSwiftReferenceCounting(Clas)) {
fieldOffset = Clas->getFieldOffsets()[i];
} else {
#if SWIFT_OBJC_INTEROP
Ivar *ivars = class_copyIvarList(
reinterpret_cast<Class>(const_cast<ClassMetadata *>(Clas)), nullptr);
fieldOffset = ivar_getOffset(ivars[i]);
free(ivars);
#else
swift::crash("Object appears to be Objective-C, but no runtime.");
#endif
}
return (intptr_t)fieldOffset;
}
這里面是調(diào)用TargetStructMetadata中的getFieldOffsets函數(shù)源碼如下:
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);
}
我們可以看到這里統(tǒng)一是通過(guò)獲取Description中的屬性,這里使用的屬性是FieldOffsetVectorOffset。獲取到偏移值后通過(guò)內(nèi)存偏移即可獲取到屬性值。
四、還原StructMetadata
4.1 TargetStructMetadata
首先我們需要擁有一個(gè)結(jié)構(gòu)體的元數(shù)據(jù)結(jié)構(gòu),這里我們命名為StructMetadata,里面有繼承的kind和Descriptor屬性,這里的Descriptor屬性是一個(gè)TargetStructDescriptor類型的指針。
struct TargetStructMetadata {
var Kind: Int
var typeDescription: UnsafeMutablePointer<TargetStructDescriptor>
}
4.2 TargetStructDescriptor
對(duì)于結(jié)構(gòu)體來(lái)說(shuō)其內(nèi)部有7個(gè)屬性
1、flag是個(gè)32位的整形,我們用Int32代替
2、parent是記錄父類的,類型TargetRelativeDirectPointer<Runtime>,這里也可以用Int32代替
3、name是記錄類型的,它的類型是TargetRelativeDirectPointer<char>,所以我們需要實(shí)現(xiàn)一個(gè)TargetRelativeDirectPointer
4、AccessFunctionPtr與name類似,內(nèi)部是個(gè)指針
5、Fields也與name類似,內(nèi)部是個(gè)FieldDescriptor
6、NumFields使用Int32
7、FieldOffsetVectorOffset也是用Int32
仿寫實(shí)現(xiàn)如下:
struct TargetStructDescriptor {
var Flags: Int32
var Parent: Int32
var Name: TargetRelativeDirectPointer<CChar>
var AccessFunctionPtr: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
var NumFields: Int32
/// 每一個(gè)屬性距離當(dāng)前實(shí)例對(duì)象地址的偏移量
var FieldOffsetVectorOffset: Int32
var genericArgumentOffset: Int {
return 2
}
}
4.3 TargetRelativeDirectPointer
-
TargetRelativeDirectPointer是RelativeDirectPointer的別名,其內(nèi)部有一個(gè)繼承的RelativeOffset屬性,是int32_t類型,我們可以用Int32代替。 - 還有一個(gè)
get方法,內(nèi)部通過(guò)指針偏移獲取值。
struct TargetRelativeDirectPointer<Pointee> {
var offset: Int32
///模擬RelativeDirectPointerImpl類中的get方法 this+offset指針
mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {
let offset = self.offset
return withUnsafePointer(to: &self) { p in
/*
獲得self,變?yōu)閞aw,然后+offset
- UnsafeRawPointer(p) 表示this
- advanced(by: numericCast(offset) 表示移動(dòng)的步長(zhǎng),即offset
- assumingMemoryBound(to: T.self) 表示假定類型是T,即自己指定的類型
- UnsafeMutablePointer(mutating:) 表示返回的指針類型
*/
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))
}
}
}
4.4 FieldDescriptor
FieldDescriptor在Mirror反射中有著很重要的作用,其內(nèi)部有5個(gè)屬性:
-
MangledTypeName是RelativeDirectPointer<const char>類型,我們使用TargetRelativeDirectPointer<CChar>代替 -
Superclass與MangledTypeName一樣 -
Kind是FieldDescriptorKind類型,實(shí)際是uint16_t,這里我們使用UInt16代替 -
FieldRecordSize是UInt16也使用使用UInt16代替 -
NumFields使用Int32代替 -
fields,其實(shí)從屬性上看不到有這個(gè),但是這里面有個(gè)getFieldRecordBuffer方法,通過(guò)this+1的方式一個(gè)一個(gè)的訪問屬性,所以這是一塊連續(xù)的內(nèi)存空間,我們使用fields代替
struct FieldDescriptor {
var MangledTypeName: TargetRelativeDirectPointer<CChar>
var Superclass: TargetRelativeDirectPointer<CChar>
var Kind: UInt16
var FieldRecordSize:UInt16
var NumFields: UInt32
var fields: FiledRecordBuffer<FieldRecord>
}
4.5 FieldRecord
FieldRecord存儲(chǔ)著屬性的相關(guān)信息,其內(nèi)部有三個(gè)屬性
-
Flags是FieldRecordFlags類型實(shí)際是uint32_t,這里我們使用Int32代替 -
MangledTypeName使用TargetRelativeDirectPointer<CChar>代替 -
FieldName使用TargetRelativeDirectPointer<CChar>代替
struct FieldRecord {
var Flags: UInt32
var MangledTypeName: TargetRelativeDirectPointer<CChar>
var FieldName: TargetRelativeDirectPointer<CChar>
}
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))
}
}
}
五、打印屬性信息和屬性值
定義一個(gè)結(jié)構(gòu)體:
struct ZGPerson {
var age: Int = 18
var name: String = "Zhang"
}
var p = ZGPerson()
5.1 綁定結(jié)構(gòu)體內(nèi)存
使用unsafeBitCast按位強(qiáng)轉(zhuǎn),將ZGPerson綁定到StructMetadata上,注意,這個(gè)操作非常危險(xiǎn),沒有任何校驗(yàn)和修飾。
let ptr = unsafeBitCast(ZGPerson.self as Any.Type, to: UnsafeMutablePointer<TargetStructMetadata>.self)
5.2 打印類名和屬性個(gè)數(shù)
let typeDescription = ptr.pointee.typeDescription
let namePtr = typeDescription.pointee.Name.getmeasureRelativeOffset()
print("current class name: \(String(cString: namePtr))")
let numFields = typeDescription.pointee.NumFields
print("當(dāng)前類屬性的個(gè)數(shù):\(numFields)")
5.3 打印屬性名稱和屬性值
1、打印一下屬性的名稱,首先是獲取到FieldDescriptor的指針,然后通過(guò)內(nèi)存偏移的方式訪問每一個(gè)FieldRecord,最后再訪問FieldRecord中的屬性名。
2、打印屬性值:
- 首先獲取
FieldOffsetVectorOffset的值 - 然后再加上
this也就是當(dāng)前Metadata的指針 - 這里我們將仿寫的
StructMetadata的指針ptr重綁定為Int - 源碼中加上
FieldOffsetVectorOffset,這里我們就移動(dòng)FieldOffsetVectorOffset - 然后將上述移動(dòng)后的綁定為一個(gè)
Int32的指針 - 最后使用
UnsafeBufferPointer和屬性個(gè)數(shù)創(chuàng)建一個(gè)buffer數(shù)組指針 - 接下來(lái)我們就可以從數(shù)組中取出每個(gè)屬性的
偏移值 - 然后取出結(jié)構(gòu)體實(shí)例
p的內(nèi)存地址 - 然后按照
buffer數(shù)組中的偏移值進(jìn)行偏移,重綁定為屬性的類型 - 最后就可以打印出
屬性值了
var bufferPtr = UnsafeBufferPointer(start: UnsafeRawPointer(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self).advanced(by: numericCast(ptr.pointee.typeDescription.pointee.FieldOffsetVectorOffset))).assumingMemoryBound(to: Int32.self), count: Int(ptr.pointee.typeDescription.pointee.NumFields))
for i in 0 ..< numFields {
let fieldDespritor = typeDescription.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.FieldName.getmeasureRelativeOffset()
print("--- fixed \(String(cString: fieldDespritor)) info begin ---")
let mangledTypeName = typeDescription.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.MangledTypeName.getmeasureRelativeOffset()
let genericVector = UnsafeRawPointer(ptr).advanced(by: typeDescription.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
let fieldType = swift_getTypeByMangledNameInContext(mangledTypeName, 256, UnsafeRawPointer(typeDescription), UnsafeRawPointer(genericVector).assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
let type = unsafeBitCast(fieldType, to: Any.Type.self)
let value = customCast(type: type)
let fieldOffset = bufferPtr[Int(i)]
let valuePtr = withUnsafeMutablePointer(to: &p) { $0 }
print("fieldType: \(type) \nfieldValue: \(value.get(from: UnsafeRawPointer(UnsafeRawPointer(valuePtr).advanced(by: numericCast(fieldOffset)))))")
print("--- field: \(String(cString: fieldDespritor)) info end ---\n")
}
本文部分資料參考了下列文獻(xiàn)
作者:憤怒的apple
鏈接:https://juejin.cn/post/7052644744693809183/
來(lái)源:稀土掘金



