Cool Swift Tricks 1: Mirror, Mirror

This is the first of four posts about random little Swift tips and tricks for you to amaze your friends and confound your enemies. All of these came up in my real code recently, and they really did surprise one or more of my co-workers. The Swift language has a lot of cool features hidden away in its nooks and crannies, but most real developers are too busy getting real work done to keep up with all of them; so every once in a while I’ve submitted a pull request that made someone say, “Hey, I didn’t know about that!” If you already knew about these features, you can feel smug, and if you didn’t, now you do, so you can feel smug anyway.


We had a bunch of value types in our app, basically just collections of properties. While debugging, these would all print out nicely in the LLDB console as a list of their properties along with their values — except for one. After a while, I realized what the problem was: the ones that printed out nicely were structs, but the problematic one was a class.

For example:

struct Person {
    let name: String
    let age: Int
    let pet: Pet
}

class Pet {
    let name: String
    let license: Int
    init(name:String, license:Int) {
        self.name = name; self.license = license
    }
}

let pet = Pet(name: "Speedy", license: 123)
let person = Person(name: "Lear", age: 80, pet: pet)

Now in LLDB we try to examine person, and here’s what we get:

(lldb) po person
▿ Person
  - name : "Lear"
  - age : 80
  ▿ pet : <Pet: 0x600001a22040>

So LLDB is happy to give me a property-based picture of a Person, but not of a Pet. I have no idea why that is. Now, you could say, “Call dump“; but there’s no time for that, because I have lots of these Pet objects popping up all the time. You could also say, “Write a description property for Pet”; but there’s no time for that either, because in real life this class has a lot of properties — and besides, if we add or remove a property, I have to remember to rewrite my description implementation.

What I do have time for is to whip up a protocol that uses Mirror introspection to report on a type’s properties in general, without my having to specify what they are:

protocol Introspectable: CustomDebugStringConvertible {}
extension Introspectable {
    var debugDescription: String {
        var output = ""
        for child in Mirror(reflecting: self).children {
            output += (child.label ?? "") + ": " + String(describing: child.value) + "n"
        }
        return output
    }
}

Now all I have to do is declare that Pet conforms to Introspectable, thereby injecting my definition of debugDescription into it. The po command in LLDB uses debugDescription if it exists, so now here’s what happens in LLDB:

(lldb) po person
▿ Person
  - name : "Lear"
  - age : 80
  ▿ pet : name: Speedy
    license: 123

It’s not elegant, and the formatting isn’t perfect, but at least I see the Pet properties and their values so I can get on with debugging the app. Even better, it surprised a colleague, who didn’t know that Mirror could be put to such a practical use.

Check out part 2 of Cool Swift Tricks: No Escape

You Might Also Like…

Swift 5.5: Replacing GCD With Async/Await

Multithreading! The mere word sends shivers up one’s spine. And if it doesn’t, it should. Main thread and background threads. Code that runs asynchronously. Code that can run simultaneously with other code. Code that can run simultaneously with itself. Code that can share data across threads — possibly with disastrous consequences. Concurrency. Multithreaded code is …

Swift 5.5: Replacing GCD With Async/Await Read More »

    Sign Up

    Get more articles and exclusive content that takes your iOS skills to the next level.