Logs are important.
It is also important to keep these logs as readable and understandable as possible. Wouldn’t it be great if whenever we try to print an object to the console we will get an exact description of the object? Including all of it’s properties and their current values?
Let’s do just that!
I’ll use a simple Dog class and Xcode’s Playgrounds to show you how it’s done.
Our Dog class has three constant properties. When a Dog object is initialized all of these properties are filled with values passed to the init method.
What will happen if we try to print a Dog instance to the console?
I created a couple of different Dog instances but when I print them I get exactly the same result — “Dog”. Not only this is not very informative - but I can’t even see the different values for each of these Dog instances.
I don’t really have a way to distinguish between Brono the dog and Wendy the dog.
How will we ever be able to overcome this :O?
Wait! I remember some Swift protocol called printable! That sounds like something I would want. I also remember Apple changed the name of the protocol from the friendly printable name to CustomStringConvertible.
Looks like I’m missing something.
Currently my Dog class is not conforming to the CustomStringConvertible protocol. Why is that? According to Apple’s documentation I need to create a description String which will be a textual representation of self.
Now, when I’ll print the both Dog instances I will get different results
That’s great. Much much better.
Problem is I would have to do this for every class individually. I will also have to remember to update the description override in case of adding or removing properties. That’s no fun.
In order to automate this whole thing — we can create a protocol extension for the CustomStringConvertible protocol.
Using Swift’s reflection capabilities we print the class’ name, iterate through the properties and print their values. I like to add a few asterixes to the class’ name in order to differentiate it from what’s coming next.
The new print result will look great — and we didn’t have to write any custom code for each specific class.
Address in memory
In some cases — specifically when I’m dealing with reference type classes — I would like to also see the address of the instance (could be helpful when I’m trying to make sure no one is replacing the instance I’m currently working on with a different one). Adding the memory address to the log is easy.
Now when we print reference type — we will also see the address in memory of that specific instance.
Only thing left to take care of is cases of superclass.
Our CustomStringConvertible protocol extension only takes care of a class’ properties but leaves the superclass’ properties out of the picture. Going through selfMirror.superclassMirror will help us take care of that.
Give it a shot and finish implementing this yourself!
Do note — if your objects are inheriting from NSObject the description function will be called by default. In this case you will need to extend the NSObject class instead of the CustomStringConvertible protocol.
As I try to keep my code pure Swift (where possible) the CustomStringConvertible protocol is needed.