The Swift Reflection API and what you can do with it

What is in a Mirror

released Fri, 01 Mar 2019
Swift Version 5.0

What is in a Mirror

The Mirror struct contains several types to help you identify the information you'd like to query.

The first one is the DisplayStyle enum which tells you the type of the subject:

public enum DisplayStyle {

     case `struct`

     case `class`

     case `enum`

     case tuple

     case optional

     case collection

     case dictionary

     case set

}

Those are the supported types of the reflection API. As we saw earlier, reflection only requires an Any type, and there're many things in the Swift standard library that are of type Any but aren't listed in the DisplayStyle enum above. What happens when you try to reflect over one of those, say a closure?

let closure = { (a: Int) -> Int in return a * 2 }

let aMirror = Mirror(reflecting: closure)

In this case, you'd get a mirror, but the DisplayStyle would be nil 1

There's also a typealias for the child elements of a Mirror:

public typealias Child = (label: String?, value: Any)

So each child consists out of an optional label and a value of type Any. Why would the label be an Optional? If you think about it, it makes sense, not all of the structures that are supported by reflection have children with names. A struct has the property's name as the label, but a Collection only has indexes, not names. Tuples are a little bit special. In Swift values in tuple could have optional labels. Doesn't matter if value in tupple is labeled or not, in reflection tuple will have labels ".0", ".1" and so on.

Next up is the AncestorRepresentation enum:

public enum AncestorRepresentation {

     /// Generate a default mirror for all ancestor classes.  This is the

     /// default behavior.

     case generated

     /// Use the nearest ancestor's implementation of `customMirror()` to

     /// create a mirror for that ancestor.      

     case customized(@escaping () -> Mirror)

     /// Suppress the representation of all ancestor classes.  The

     /// resulting `Mirror`'s `superclassMirror()` is `nil`.

     case suppressed

}

This enum is used to define how superclasses of the reflected subject should be reflected. I.e. this is only used for subjects of type class. The default (as you can see) is that Swift generates an additional mirror for each superclass. However, if you need more flexibility here, you can use the AncestorRepresentation enum to define how superclasses are being mirrored.