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 & 错误处理!

Swift之深入解析反射Mirror的底层原理

Swift之深入解析反射Mirror与错误处理

解决Jupyter notebook报错:AssertionError: wrong color format ‘var(--jp-mirror-editor-variable-color)‘(代码片

Swift - Alamofire源码解析

Swift - Alamofire源码解析