Swift Runtime探索
class XQTeacher {
var age = 18
func teach() {
print("teach")
}
}
func test() {
var properCount : UInt32 = 0
let properList = class_copyPropertyList(XQTeacher.self, &properCount)
for i in 0..<numericCast(properCount) {
if let proper = properList?[i] {
let properName = property_getName(proper)
print("属性:\(String(utf8String: properName)!)")
}else{
print("没有属性")
}
}
var methodCount : UInt32 = 0
let methodList = class_copyMethodList(XQTeacher.self, &methodCount)
for i in 0..<numericCast(methodCount) {
if let method = methodList?[i] {
let methodName = method_getName(method)
print("方法名:\(String(describing: methodName))")
}else{
print("没有方法")
}
}
}
test()
print("end")
- 运行这段代码你会发现,当前不管是我们的方法列表还是我们的属性列表,此次此刻都是为空的
- 在Swift值类型和引用类型、方法调度中我们知道
@objc的作用,如果这个时候我们将我们当前的方法和属性添加上@objc,会发生什么?

- 此刻代码会输出我们当前的
teach方法和age属性。但是此刻对于我们的oc来说是没有办法使用的,还得将class继承自NSObject
总结
- 对于纯
Swift类来说,是不具备动态特性。方法和属性不加任何修饰符的情况下。这个时候其实已经不具备我们所谓的runtime特性了。
- 对于纯
Swift类,方法和属性添加@objc标识的情况下,当前我们可以通过Runtime API拿到,但是在oc中是没法进行调度的。
- 对于继承自
NSObject类来说,如果我们想要动态的获取当前的属性和方法,必须在其声明前添加@objc关键字,方法交换: dynamic的标识。否则也是没有办法通过Runtime API获取的。
SwiftObject
- 通过源码调试,在
class_copyPropertyList方法执行的时候打下断点,运行进入断点

- 进到
class_copyPropertyList方法

- 进入到
data方法,可以看到swift有一个默认的基类_SwiftObject

- 在
Swift源码里面搜索_SwiftObject

TargetAnyClassMetadata里面的成员

Swift为了和oc交互,在底层存储的数据结构上是和oc保持了部分一致。
- 在
objc源码中也有swift_class_t的定义,它是一个继承自objc_class的结构体,也就是在objc_class的成员变量的基础上加上自己的成员变量

反射
- 反射就是可以动态获取类型、成员信息,在运行时可以调用方法、属性等行为的特性。上面我们分析过了,对于一个纯
Swift类来说,并不支持我们直接像oc那样操作;但是Swift标准库依然提供了反射机制让我们访问成员信息, 反射的用法非常简单。
class XQTeacher {
var age = 18
}
var t = XQTeacher()
let mir = Mirror(reflecting: t)
for pro in mir.children {
print("\(String(describing: pro.label)):\(pro.value)")
}
func test(_ obj:Any) -> Any {
let mirror = Mirror(reflecting: obj)
guard !mirror.children.isEmpty else {
return obj;
}
var keyValue : [String:Any] = [:]
for child in mirror.children {
if let keyName = child.label {
keyValue[keyName] = test(child.value)
}else{
print("label为空")
}
}
print(keyValue)
return keyValue
}
test(t)
protocol CustomJSONMap {
func jsonMap() -> Any
}
extension CustomJSONMap {
func jsonMap() -> Any {
let mirror = Mirror(reflecting: self)
guard !mirror.children.isEmpty else {
return self;
}
var keyValue : [String:Any] = [:]
for child in mirror.children {
if let value = child.value as? CustomJSONMap {
if let keyName = child.label {
keyValue[keyName] = value.jsonMap()
}else{
print("label为空")
}
}else{
print("没有遵守协议")
}
}
print(keyValue)
return keyValue
}
}
class XQTeacher : CustomJSONMap{
@objc var age = 18
@objc func teach() {
print("teach")
}
}
extension Int : CustomJSONMap {}
var t = XQTeacher()
let result = t.jsonMap()
---------
错误处理
- 在上文的json解析中,我们没有对错误进行处理只是打印了,定义一个
JSONMapError,错误的抛出我们一般使用throw。
enum JSONMapError : Error {
case emptyKey
case notConformProtocol
}
protocol CustomJSONMap {
func jsonMap() throws -> Any
}
extension CustomJSONMap {
func jsonMap() throws -> Any {
let mirror = Mirror(reflecting: self)
guard !mirror.children.isEmpty else {
return self;
}
var keyValue : [String:Any] = [:]
for child in mirror.children {
if let value = child.value as? CustomJSONMap {
if let keyName = child.label {
keyValue[keyName] = try? value.jsonMap()
}else{
throw JSONMapError.emptyKey
}
}else{
throw JSONMapError.notConformProtocol
}
}
return keyValue
}
}
class XQTeacher : CustomJSONMap{
@objc var age = 18
var height = 1.98
@objc func teach() {
print("teach")
}
}
extension Int : CustomJSONMap {}
var t = XQTeacher()
let result = try? t.jsonMap()
print(result)
元类型、AnyClass、Self
AnyObject:代表任意类的instance,类的类型,仅类遵守的协议
Any:代表任意类型,包括funcation类型或者Optional类型
AnyClass:代表任意实例的类型
T.self:如果T是实例对象,返回的就是它本身;如果T是类,返回的就是元类型(MetaData)
T.Type:一种类型,T.self是T.Type类型
type(of:):用来获取一个值的动态类型