这是我参与更文挑战的第26天,活动详情查看: 更文挑战
前言
反射是指可以动态获取类型、成员信息,同时在运行时(而非编译时)可以动态调用任意方法、属性等行为的特性。
在对于iOS开发人员来说, 使用 OC 开发时很少强调其反射概念,因为 OC 的 runtime 要比其他语言中的反射强大的多,在 OC 中可以很简单的实现字符串和类型的转换(NSClassFromString()),实现动态方法调用(performSelector: withObject:),动态赋值(KVC)等等。
对于纯 Swift 类来说,并不支持像 OC runtime 那样操作,但是 Swift 标准库仍然提供了反射机制访问成员信息,即 Mirror。
1. Mirror 简介
Mirror
是Swift
中的反射机制的实现,它的本质是一个结构体。
public struct Mirror {
/// A suggestion of how a mirror's subject is to be interpreted.
///
/// Playgrounds and the debugger will show a representation similar
/// to the one used for instances of the kind indicated by the
/// `DisplayStyle` case name when the mirror is used for display.
public enum DisplayStyle {
case `struct`, `class`, `enum`, tuple, optional, collection
case dictionary, `set`
}
/// The static type of the subject being reflected.
///
/// This type may differ from the subject's dynamic type when this mirror
/// is the `superclassMirror` of another mirror.
public let subjectType: Any.Type
/// A collection of `Child` elements describing the structure of the
/// reflected subject.
public let children: Children
/// A suggested display style for the reflected subject.
public let displayStyle: DisplayStyle?
/// A mirror of the subject's superclass, if one exists.
public var superclassMirror: Mirror? {
return _makeSuperclassMirror()
}
}
复制代码
subjectType
:表示类型,被反射主体的类型children
:子元素集合displayStyle
:显示类型,基本类型为nil 枚举值:struct, class, enum, tuple, optional, collection, dictionary, set
superclassMirror
:父类反射, 没有父类为nil
2. Mirror的简单使用
这里我们通过使用Mirror
打印对象的属性名称和属性值。
class Person {
var name: String = "xiaohei"
var age: Int = 18
var height = 1.85
}
var p = Person()
var mirror = Mirror(reflecting: p.self)
print("对象类型:\(mirror.subjectType)")
print("对象属性个数:\(mirror.children.count)")
print("对象的属性及属性值")
for child in mirror.children {
print("\(child.label!)---\(child.value)")
}
复制代码
打印结果
对象类型:Person
对象属性个数:3
对象的属性及属性值
name---Jay Chou
age---42
height---1.75
复制代码
3. 将对象转换为字典
class Animal {
var location: String = "亚洲"
var like: [String] = ["mouse", "fish"]
private var birthday: Int = 1979
}
class Person : Animal {
... 省略
func modelToMap(mirror: Mirror) -> [String: Any] {
var map: [String: Any] = [:]
for child in mirror.children {
// 如果没有labe就会被抛弃
if let label = child.label {
let propertyMirror = Mirror(reflecting: child.value)
print(propertyMirror)
map[label] = child.value
}
}
// 添加父类属性
if let superMirror = mirror.superclassMirror {
let superMap = modelToMap(mirror: superMirror)
for p in superMap {
map[p.key] = p.value
}
}
return map
}
let mirrorDic = modelToMap(mirror: mirror)
print(mirrorDic)
复制代码
对象转Map
Mirror for String
Mirror for Int
Mirror for Double
Mirror for String
Mirror for Array<String>
Mirror for Int
["location": "亚洲", "height": 1.75, "age": 42, "birthday": 1979, "like": ["mouse", "fish"], "name": "CC"]
复制代码
对于一些基本类型,已经可选类型的数据都已经转换为字典值,对于私有属性也可以完成转换。如果里面包含类则还需要进行递归处理。比起用runtime要方便, 而且可以分别获取对象仅属于自身的属性值和从父类继承的属性值.不过暂时Swift中反射的功能远还没有runtime强大。
4.JSON 转对象
HandyJSON 中用到Mirror
static func _serializeAny(object: _Transformable) -> Any? {
let mirror = Mirror(reflecting: object)
guard let displayStyle = mirror.displayStyle else {
return object.plainValue()
}
// after filtered by protocols above, now we expect the type is pure struct/class
switch displayStyle {
case .class, .struct:
let mapper = HelpingMapper()
// do user-specified mapping first
if !(object is _ExtendCustomModelType) {
InternalLogger.logDebug("This model of type: \(type(of: object)) is not mappable but is class/struct type")
return object
}
let children = readAllChildrenFrom(mirror: mirror)
guard let properties = getProperties(forType: type(of: object)) else {
InternalLogger.logError("Can not get properties info for type: \(type(of: object))")
return nil
}
var mutableObject = object as! _ExtendCustomModelType
let instanceIsNsObject = mutableObject.isNSObjectType()
let head = mutableObject.headPointer()
let bridgedProperty = mutableObject.getBridgedPropertyList()
let propertyInfos = properties.map({ (desc) -> PropertyInfo in
return PropertyInfo(key: desc.key, type: desc.type, address: head.advanced(by: desc.offset),
bridged: instanceIsNsObject && bridgedProperty.contains(desc.key))
})
mutableObject.mapping(mapper: mapper)
let requiredInfo = merge(children: children, propertyInfos: propertyInfos)
return _serializeModelObject(instance: mutableObject, properties: requiredInfo, mapper: mapper) as Any
default:
return object.plainValue()
}
}
复制代码
参考
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END