前言
反射(Reflection)这个机制在很多语言里是一个非常重要的特性,我们可以通过反射来实现一些“骚操作”。但是在OC里面我们很少提到反射这个机制,因为我们可以用比反射更 Bug 的 Runtime 机制来实现我们想要的功能。我本人是非常喜欢通过 Runtime 来实现 Json-Model 这个功能。但是到了 Swift 的时候,发现完全没有这方面的库,于是我去网上各种扒,最后扒到 Swift 的反射是通过 Mirror 来实现的时候,我当时觉得胜利在望了啊,同时也很疑惑为什么那么多的大神没有通过这个技术来封装一个简单易用的开源库。最后发现这个 Mirror 有个致命的问题,只可读不可写。这时候回头看看苹果定义的名字还是十分恰当的,这只是个可远观不可亵玩的镜像。虽然只能看不能摸,但是来都来了,总要留个记录吧。
基本用法
先上代码:
// model 定义
public class Person: NSObject {
var name: String? = ""
var sex: Int = 1
}
public class Teacher: Person {
var sessonName: String? = ""
}
public class Student: Person {
var classRoom: String = ""
}
// 测试代码
func printMirror(_ m: Mirror) {
print("===========\(m.subjectType)============")
print("superMirror: \(m.superclassMirror)")
print("dispatchStyle: \(m.displayStyle)")
var info: [String:Any] = [:]
for property in m.children {
if let key = property.label {
info[key] = property.value
} else {
info["unknow\(arc4random() % 100)"] = property.value
}
}
if info.count > 0 {
print(info)
} else {
print("没有值")
}
if m.superclassMirror == nil {
print("没有父Mirror了")
} else {
printMirror(m.superclassMirror!)
}
}
var t = Teacher()
t.sessonName = "语文"
t.name = "张三"
t.sex = 2
var mirror = Mirror(reflecting: t)
printMirror(mirror)
上面代码的调用结果如下:
===========Teacher============
superMirror: Optional(Mirror for Person)
dispatchStyle: Optional(Swift.Mirror.DisplayStyle.class)
["sessonName": Optional("语文")]
===========Person============
superMirror: Optional(Mirror for NSObject)
dispatchStyle: Optional(Swift.Mirror.DisplayStyle.class)
["sex": 2, "name": Optional("张三")]
===========NSObject============
superMirror: nil
dispatchStyle: Optional(Swift.Mirror.DisplayStyle.class)
没有值
没有父Mirror了
Mirror是一个结构体,它的的基本用法其实非常简单,通过默认的构造方法public init(reflecting subject: Any)
就可以得到一个完整的 Mirror 对象了。Mirror包含以下几个变量:
- subjectType 当前 Mirror实例 指向的对象名称
- children 当前 Mirror实例 包含的属性集合,定义为
AnyCollection<Mirror.Child>
- displayStyle 当前 Mirror实例 的类型
- superclassMirror 当前Mirror实例 的父类 Mirror对象
上面的属性中,需要注意 children 这个属性,childern 里面的值只包含当前对象的属性,并不包含它的父类的属性,如果要访问它父类的属性,需要通过 superclassMirror 来获取到父类的 Mirror,再进行获取对应的属性。
虽然现在我们还不能在使用 Swift 的 Mirror 机制来进行一些赋值等操作,但是进行一些封装的话,可以用来辅助调试。
期待以后开放给多的权限吧。
最后
以上就是本篇的内容,关于 Mirror 内部实现(源码部分)目前还没有看,感兴趣的同学可以先看下 <参考> 部分的链接,那里有比较详细的讲解。暂时只能写到这里了,欢迎斧正~
参考
https://swift.gg/2018/11/15/how-mirror-works/
https://zhuanlan.zhihu.com/p/33945268
网友评论