string conversions in swift
May 20, 2016Say you have your own custom class:
class MyClass {
let counter: Int
init(withCounter: Int) {
self.counter = withCounter
}
}
Now, you want it to be convertible to String
. One way of doing it is to create an extension to the String
class itself like this:
extension String {
init(_ myClass: MyClass) {
self = "{ counter: \(myClass.counter) }"
}
}
This will let you do:
let str = String(MyClass(withCounter:25))
// str is "{ counter: 25 }"
This may seem to be sufficient in many cases, but it does not seem to be truly the Swift way. I realised this when working with testing framework (Nimble) and I realised that having just String
extension does not make Nimble to produce correct string descriptions of my class instances when testing. In particular, and you can test it easily in the playground, this will not work as expected:
let str2 = "\(MyClass(withCounter:25))"
// str2 is "MyClass"
For the string interpolation to work as expected in this case, you would rather have to do this:
let str3 = "\(String(MyClass(withCounter:25)))"
// str3 is "{ counter: 25 }"
This is not how you want to use string interpolation though.
This blog describes how this is supposed to be done correctly in Swift 1 (still with lots of pain), and here is the updated version for Swift 2.
To summarise, this is how you can extend MyClass
:
class MyClass: CustomStringConvertible {
let counter: Int
var description: String {
return "{ counter: \(self.counter) }"
}
init(withCounter: Int) {
self.counter = withCounter
}
}
Now, the string interpolation should work as expected. You can download the gist playground file here.