-1

I want to print an object in the console in Swift.

In Java I would override the public String toString() method.

How can I do that in Swift?

class MyClass {
    var i : Int
    var j : Int
// ...
//  method to return a String {
        return String(i) + ", " + String(j)
    }
}

var mc = MyClass(5, 10)
print(mc) // 5, 10

Christoph S.
  • 585
  • 3
  • 16

3 Answers3

1

You need your entity to conform to CustomStringConvertible and implement var description.

class MyClass: CustomStringConvertible {
    var i : Int // Integer doesn't exist in swift
    var j : Int

    var description: String {
        String(i) + ", " + String(j) // return is implicit
    }
}

In general, Swift classes don't inherit from any super class, so they don't have basic methods like toString, equal and so on.

Every implementation needs to conform to a specific protocol (a java interface).

Rico Crescenzio
  • 3,952
  • 1
  • 14
  • 28
1

You need to conform to the CustomStringConvertible protocol. Then you implement the description property.

class MyClass: CustromStringConvertible {
    var i: Int
    var j: Int

    // ...

    var description: String {
        return "\(i), \(j)"
    }
}

var mc = MyClass(5, 10)
print(mc) // 5, 10

From the Apple documentation:

Types that conform to the CustomStringConvertible protocol can provide their own representation to be used when converting an instance to a string. The String(describing:) initializer is the preferred way to convert an instance of any type to a string. If the passed instance conforms to CustomStringConvertible, the String(describing:) initializer and the print(_:) function use the instance’s custom description property.

Accessing a type’s description property directly or using CustomStringConvertible as a generic constraint is discouraged.

For debugging purposes, you might want to conform to CustomDebugStringConvertible and implement debugDescription instead (documentation).

This would look like this (Playground file):

import Foundation

struct Point {
    let x: Int, y: Int
}

extension Point: CustomStringConvertible {
    var description: String {
        return "NON-DEBUG - (\(x), \(y))"
    }
}

extension Point: CustomDebugStringConvertible {
    var debugDescription: String {
        return "DEBUG - (\(x), \(y))"
    }
}

let p = Point(x: 21, y: 30)

print(p)
// NON-DEBUG - (21, 30)

print(String(reflecting: p))
// DEBUG - (21, 30)
Bjorn B.
  • 506
  • 3
  • 10
1

You'll want to use CustomStringConvertible or CustomDebugStringConvertible:

class MyClass {
    var i: Int
    var j: Int
    
    init(i: Int, j: Int) {
        self.i = i
        self.j = j
    }
}

extension MyClass: CustomStringConvertible {
    var description: String {
        "\(i), \(j)"
    }
}

extension MyClass: CustomDebugStringConvertible {
    var debugDescription: String {
        "\(i), \(j)"
    }
}

As a suggestion, if you're just going to be passing this around and don't need to hang onto it, you could change it to a value type like a struct and you'd get an initializer for free.

I'd recommend extending classes to utilize protocols like CustomStringConvertible and CustomDebugStringConvertible to keep your code neat.

Adrian
  • 16,233
  • 18
  • 112
  • 180