Swift之Mirror(反射)

这是我参与更文挑战的第26天,活动详情查看: 更文挑战

前言

反射是指可以动态获取类型、成员信息,同时在运行时(而非编译时)可以动态调用任意方法、属性等行为的特性。

在对于iOS开发人员来说, 使用 OC 开发时很少强调其反射概念,因为 OC 的 runtime 要比其他语言中的反射强大的多,在 OC 中可以很简单的实现字符串和类型的转换(NSClassFromString()),实现动态方法调用(performSelector: withObject:),动态赋值(KVC)等等。

对于纯 Swift 类来说,并不支持像 OC runtime 那样操作,但是 Swift 标准库仍然提供了反射机制访问成员信息,即 Mirror。

1. Mirror 简介

MirrorSwift中的反射机制的实现,它的本质是一个结构体。

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()
        }
    }

复制代码

参考

blog.csdn.net/Forever_wj/…

blog.csdn.net/Forever_wj/…

www.jianshu.com/p/a4ca25caa…

www.zzvips.com/article/129…

github.com/iwill/ExCod…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享