Overriding the description variable of a custom class:
override var description : String {
let mirrored_object = Mirror(reflecting: self)
let
I wouldn't use tabs but use padding(...)
:
var description : String {
let mirrored_object = Mirror(reflecting: self)
let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
let maxLen = childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0
let lines = childrenWithLabel.map { $0.label!.padding(toLength: maxLen, withPad: " ", startingAt: 0) + " = \($0.value)" }
return lines.joined(separator: "\n")
}
For a struct like
struct Foo: CustomStringConvertible
{
let userID = 42
let username = "Foo"
let verylongpropertyname: String? = "Bar"
}
this produces
userID = 42
username = Foo
verylongpropertyname = Optional("Bar")
As for the "Optional" part, it's not as easy as totiG suggests because the value you get from the mirror is of type Any
. See this question.
Update
I overlooked that you wanted to have a slightly different format.
var description : String {
let mirrored_object = Mirror(reflecting: self)
let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
let separator = " = "
let firstColumnWidth = (childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0) + separator.characters.count
let lines = childrenWithLabel.map {
($0.label! + separator).padding(toLength: firstColumnWidth, withPad: " ", startingAt: 0) + "\($0.value)"
}
}
produces
userID = 42
username = Foo
verylongpropertyname = Optional("Bar")
Update 2
To get rid of the "Optional" thing, please see my answer here.
If you use (from said answer) unwrap()
or unwrapUsingProtocol()
in description
like this:
var description : String {
let mirrored_object = Mirror(reflecting: self)
let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
let separator = " = "
let firstColumnWidth = (childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0) + separator.characters.count
let lines = childrenWithLabel.map {
($0.label! + separator).padding(toLength: firstColumnWidth, withPad: " ", startingAt: 0) + "\(unwrap($0.value))"
}
return lines.joined(separator: "\n")
}
this will produce
userID = 42
username = Foo
verylongpropertyname = Bar
Try use this method. It first calculates the max length of the property, and then uses that to pad the property names:
let maxPropertyLength: Int = mirrored_object.children.map { Int($0.label?.characters.count ?? 0) }.max() ?? 0
for attr in mirrored_object.children {
if let propertyName = attr.label {
str.append("\(propertyName.padding(toLength: maxPropertyLength + 2, withPad: " ", startingAt: 0)) = \(attr.value)\n")
}
}
return str as String