Skip to content

Instantly share code, notes, and snippets.

@mcmurrym
Last active December 24, 2019 05:59
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mcmurrym/2870c2a5ac6fd790570b to your computer and use it in GitHub Desktop.
Save mcmurrym/2870c2a5ac6fd790570b to your computer and use it in GitHub Desktop.
A default protocol implementation for CustomDebugStringConvertible that uses Mirror for introspection
public extension CustomDebugStringConvertible {
var debugDescription: String {
return debugDescription()
}
func debugDescription(_ indentationLevel: Int = 0, includeType: Bool = true) -> String {
let indentString = (0..<indentationLevel).reduce("") { tabs, _ in tabs + "\t" }
var s: String
if includeType {
s = "\(type(of: self))"
} else {
s = ""
}
let mirror = Mirror(reflecting: self)
let children = mirror.children
if children.count == 0 {
return s + " = \(debugDescription),"
}
if s.hasPrefix("Optional<") {
let child = children.first!
if let aChild = child.1 as? CustomDebugStringConvertible {
s += aChild.debugDescription(indentationLevel, includeType: false)
} else {
s += "\(child.1),"
}
s += "\(indentString)"
} else if let date = self as? Date {
s += " = \(date),"
} else {
s += " {"
var index = 0
s = children.reduce(s) { reducedString, child in
var propertyName: String = ""
if self is Array<Any> {
propertyName = String(index)
index += 1
} else {
propertyName = child.label ?? "<undefined>"
}
if let aChild = child.value as? CustomDebugStringConvertible {
let childDescription = aChild.debugDescription(indentationLevel + 1)
return reducedString + "\n\(indentString)\t\(propertyName): \(childDescription)"
} else {
return reducedString + "\n\(indentString)\t\(propertyName): \(type(of: child.value)) = \(child.value),"
}
}
s = s.substring(to: s.characters.index(before: s.characters.endIndex))
s += "\n\(indentString)}"
}
return s
}
}
/*
// Sample usage
struct Person: CustomDebugStringConvertible {
let name: String
let address: Address
let children: [Person]?
}
struct Address: CustomDebugStringConvertible {
let city: String
let state: String
let zip: String
let streetNumber: String
let streetName: String
let suiteNumber: String?
let randomNumber: Int
init(city: String, state: String, zip: String, streetNumber: String, streetName: String, suiteNumber: String? = nil) {
self.city = city
self.state = state
self.zip = zip
self.streetNumber = streetNumber
self.streetName = streetName
self.suiteNumber = suiteNumber
self.randomNumber = Int(arc4random_uniform(1000))
}
}
let address = Address(city: "Lehi", state: "UT", zip: "84043", streetNumber: "123", streetName: "Fake st")
print(address)
let child = Person(name: "joe", address: address, children: nil)
let person = Person(name: "matt", address: address, children: [child])
print(person)
*/
@thomasneuteboom
Copy link

+1. Thanks for this. Would be cool if it would also provide it's super class variables as an optional parameter in the function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment