Swift mirroring

:  ~ 2 min read

I recently added some tests to LTHRadioButton, and I gave mirroring a try, something I always wanted to do. What's mirroring? As Apple puts it, it's a representation of the sub-structure and optional "display style" of any arbitrary subject instance.

Benedikt has a really nice and comprehensive post about it, so I'll just very shortly cover the children of a mirror. What are children? All the properties of an object, no matter if they are public, internal, or private. And this is where mirroring becomes interesting, and powerful: you can get access to the private / internal properties of an object - something I don't recommend on production code, unless really needed, and you're 110% sure of what you're doing. But for testing and debugging purposes, they're really, really great. One caveat, though, is that computed properties are not visible in mirrors.

Since LTHRadioButton is an open source library, I wanted to have proper access levels for its properties, but I also wanted to cover it with tests, which is why I turned to mirroring. Initialising one and accessing its children is pretty straightforward:

let radioButton = LTHRadioButton()
let mirror = Mirror(reflecting: radioButton)
mirror.children.forEach { child in
    print(child.label)
    print(child.value)
}

The label of a child is an Optional String, and it represents the property's name; the value of a child represents the object itself, and it's of type Any. The latter would then be optionally casted to the required type, and used as needed:

[...]
mirror.children.forEach { child in
    switch child.label {
    case "innerCircle"?:
        guard let innerCircle = child.value as? UIView else { return XCTFail() }
        XCTAssertEqual(innerCircle.layer.borderColor, UIColor.blue.cgColor)
    [...]
    default: return
    }
}

There's much more to mirroring, like modifying the properties of an object, for example, which is why I suggest you read Benedikt's post about it.