This is the 26th day of my participation in Gwen Challenge

preface

Reflection is the ability to dynamically retrieve type, member information, and dynamically invoke arbitrary methods, properties, and other behavior at run time (rather than compile time).

The OC runtime is much more powerful than reflection in other languages. String and type conversions (NSClassFromString()) can be easily implemented in OC. Implement dynamic method calls (performSelector: withObject), dynamic assignment (KVC), and so on.

For pure Swift classes, operations like the OC Runtime are not supported, but the Swift standard library still provides a reflection mechanism to access member information, namely Mirror.

1. Introduction of Mirror

Mirror is an implementation of the reflection mechanism in Swift, which is essentially a structure.

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

Copy the code
  • subjectType: represents the type, the type of the reflected subject
  • children: Collection of child elements
  • displayStyleDisplay type, base type nil enumeration value:struct, class, enum, tuple, optional, collection, dictionary, set
  • superclassMirror: Parent reflection, no parent is nil

2. Simple use of Mirror

Here we print the property names and property values of the object by using Mirror.

class Person {
    var name: String = "xiaohei"
    var age: Int = 18
    var height = 1.85
}

var p = Person(a)var mirror = Mirror(reflecting: p.self)

print("Object type:\(mirror.subjectType)")
print("Number of object attributes:\(mirror.children.count)")
print("Object properties and property values")
for child in mirror.children {
    print("\(child.label!)---\(child.value)")}Copy the code

Print the result

Number of object properties: Person3Object attribute and attribute value name-- Jay Chou Age --- 42
height--1.75
Copy the code

3. Convert objects to dictionaries

class Animal {
    var location: String = "Asian"
    var like: [String] = ["mouse"."fish"]
    private var birthday: Int = 1979
}
class Person : Animal {
.omitfunc modelToMap(mirror: Mirror)- > [String: Any] {
    var map: [String: Any] = [:]
    for child in mirror.children {
        // If there is no labE, it will be discarded
        if let label = child.label {
            let propertyMirror = Mirror(reflecting: child.value)
            print(propertyMirror)
            map[label] = child.value
        }
    }
    // Add a parent attribute
    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)
Copy the code
Map Mirror for String Mirror for Int Mirror for Double Mirror for String Mirror for Array<String> Mirror for Int ["location": "Asian"."height": 1.75."age": 42."birthday": 1979."like": ["mouse"."fish"]."name": "CC"]
Copy the code

For some basic types, data that is already selectable has been converted to dictionary values, and for private attributes, conversion can also be done. If it contains classes, you need to recurse. It is more convenient than using runtime, and you can get property values that belong only to the object and property values that inherit from its parent. But for now reflection in Swift is nowhere near as powerful as Runtime.

4. Turn the JSON object

HandyJSON uses 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(a)// 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()
        }
    }

Copy the code

reference

Blog.csdn.net/Forever_wj/…

Blog.csdn.net/Forever_wj/…

www.jianshu.com/p/a4ca25caa…

www.zzvips.com/article/129…

Github.com/iwill/ExCod…