Swift-进阶 07:Mirror源码解析
Posted Style月月专栏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift-进阶 07:Mirror源码解析相关的知识,希望对你有一定的参考价值。
本文主要是分析Mirror的底层实现,以及根据Mirror底层原理仿写其结构的实现
在Swift-进阶 06:反射Mirror & 错误处理文章中,我们介绍了Mirror的使用,即JSON解析,对此我们有如下一些疑问:
1、系统是如何通过
Mirror
获取对应的属性以及值的?2、Swift众所周知是一门静态语言,系统在底层到底做了什么,使swift具有了反射的特性呢?
下面我们来对Mirror的底层实现进行探索
Mirror底层源码分析
反射的API
主要是由两部分实现的
一部分是通过Swift实现,即
ReflectionMirror.swift
一部分是通过C++实现,即
ReflectionMirror.mm
两者之间是通过暴露给swift的C++函数进行通信,即
@_silgen_name
修饰符会通知swift编译器将这个swift函数映射成C++函数的符号Mirror的源码是在
Mirror.swift
文件中,路径为swift->stdlib->public->core->Mirror.swift
swift 使用技巧
使用@_silgen_name
关键字声明的方法,实际调用是括号中的方法,例如swift_cjl_add
实际调用的是c中的cjl_add
通过C定义一个方法,在swift中使用
<!--1、定义c方法-->
//.h声明
int cjl_add(int a, int b);
//.c中实现
int cjl_add(int a, int b){
return a+b;
}
<!--2、桥接文件中引入头文件-->
#import "test.h"
<!--3、swift使用-->
var value = cjl_add(10, 20)
print(value)
<!--4、打印结果-->
30
可以将上述代码中的第2步去掉删除,采用
@_silgen_name
关键字
<!--1、swift中针对cjl_add方法的声明-->
//通过@_silgen_name声明
@_silgen_name("cjl_add")
func swift_cjl_add(_ a: Int32, _ b: Int32) -> Int32
<!--2、使用-->
var value = swift_cjl_add(20, 30)
print(value)
<!--3、打印结果-->
50
分析Mirror
在
Mirror.swift
文件中找到Mirror
,是一个结构体类型Mirror结构体
查找其初始化方法
public init(reflecting subject: Any)
public init(reflecting subject: Any) {
//判断 subject 是否符合 CustomReflectable动态类型
if case let customized as CustomReflectable = subject {
//如果符合,则由 customMirror 确定属性
self = customized.customMirror
} else {
//如果不符合,则由语言生成
self = Mirror(internalReflecting: subject)
}
}
查找
internalReflecting
方法(路径为swift->stdlib->public->core->ReflectionMirror.swift
)
extension Mirror {
// Mirror的初始化器中检索需要的信息
/*
- subject 将要被反射的值
- subjectType 将要被反射的subject值的类型,通常是值的运行时类型
-
*/
internal init(internalReflecting subject: Any,
subjectType: Any.Type? = nil,
customAncestor: Mirror? = nil)
{
//根据_getNormalizedType获取传入的subject的真正类型,其中type(of: subject)获取的动态类型
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
// 获取属性大小
let childCount = _getChildCount(subject, type: subjectType)
// 遍历,将属性存储到字典中
let children = (0 ..< childCount).lazy.map({
// getChild函数时C++的_getChild 函数的简单封装,将标签名字中包含的C字符串转换为Swift字符串
getChild(of: subject, type: subjectType, index: $0)
})
// 赋值给Mirror的属性children
self.children = Children(children)
// 设置父类反射
self._makeSuperclassMirror = {//按需求构建父类的Mirror的闭包
// 获取传入对象的类
guard let subjectClass = subjectType as? AnyClass,
// 获取父类
let superclass = _getSuperclass(subjectClass) else {
return nil//非类的类型、没有父类的类的Mirror,会获取到nil
}
// 调用者可以用一个可作为父类的Mirror直接返回Mirror实例来指定自定义的祖先的表现
// 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
}
}
// 给相同值返回一个将 superclass作为 subjectType的新的Mirror
return Mirror(internalReflecting: subject,
subjectType: superclass,
customAncestor: customAncestor)
}
// 获取并解析显示的样式,并设置Mirror的其他属性
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
}
// 快速查找
internal static func quickLookObject(_ subject: Any) -> _PlaygroundQuickLook? {
#if _runtime(_ObjC)
let object = _getQuickLookObject(subject)
return object.flatMap(_getClassPlaygroundQuickLook)
#else
return nil
#endif
}
}
以上是关于Swift-进阶 07:Mirror源码解析的主要内容,如果未能解决你的问题,请参考以下文章
iOS开发-Swift进阶之反射Mirror & 错误处理!
解决Jupyter notebook报错:AssertionError: wrong color format ‘var(--jp-mirror-editor-variable-color)‘(代码片