Reflection in Swift
By: Steven Curtis
Tags: Swift, Mobile App Development

Uses of mirror in Swift

Inspect type data of structs or classes

Basically we can query data in our code. That means we can read through the list of properties that are available at runtime. Here we

enum Species {

case dog

case cat

} struct Animal {

var name: String

var species: Species

} var taylor = Animal(name: "Derek", species: .dog)

var mirror = Mirror(reflecting: taylor) print (mirror) // "Mirror for Animal"

The printing here that prints to the console “Mirror for Animal” is not too interesting. The result that you should be looking for is to iterate through the mirror to print out the properties of the Animal struct.

for case let (label?, value) in mirror.children {

print (label, value) // "name Derek", "species dog"

}

Iterate over tuples inspecting elements using Mirror

Tuples are finite ordered lists of elements, that can store different data types.

// Tuples can take different Types of data let tuple = (1, 2, "3")

let tupleMirror = Mirror(reflecting: tuple)

let tupleElements = tupleMirror.children.map({ $0.value })

tupleElements // [1, 2, "3"]

tupleElements here has the type [Any] so we can actually print out those elements that appear to have different types. Fantastic!

Inspect type data of structs or classes

We can read the data that is in our object. The mirror isn’t a copy of the object, rather a mirror that can be inspected.

let trevor = Animal(name: "trevor", species: .dog(breed: "Shetland"))

let trevMirror = Mirror(reflecting: trevor)

for case let (label?, value) in trevMirror.children {

print (label, value) // "name trevor", "species dog(breed: "Shetland")"

}

So we are printing to the console two elements:

“name trevor”

“species dog(breed: “Shetland”)”

Runtime analysis of object conformance

We are outputting the types in the following code block

let trevor = Animal(name: “trevor”, species: .dog(breed: “Shetland”))

for property in Mirror(reflecting: trevor).children {

print("name: \(String(describing: property.label)) type: \(type(of: property.value))")

}

So we are printing to the console two elements:

name: Optional(“name”) type: String

name: Optional(“species”) type: Species

Testing

We can mirror a class and then put some conditions in to the test cases.

let aMirror = Mirror(reflecting: trevor)

aMirror.children.count

Debugging with CustomReflectable

If you are for any unreason unhappy with the default Mirror, you can conform to CustomReflectable and return a custom mirror.

An example of this is debugging self

po self

this can give a less than helpful description

<MemoryTest.ViewController: 0x7ffe1f607010>

so to give this a little more information we can write an extension for the viewcontroller:

extension UIViewController: CustomReflectable{ public var customMirror: Mirror { let children = KeyValuePairs<String, Any>(dictionaryLiteral:("title", title!)) return Mirror(NSUserActivity.self, children: children, displayStyle: .class, ancestorRepresentation: .suppressed) } }

which of course relies upon you having set a title in your view controller instance!

This then returns the (very marginally) more useful po

(lldb) po self ▿ <MemoryTest.ViewController: 0x7fdc5cc06690> - title : "mytitle"

Converting structs to Core Data

This may not be the most performant thing you can do, however it is possible. I can’t write a better document than is written here, and recommend that you go there for full details.