Fun with print() in Swift

Written by Reinder de Vries on November 5 2020 in App Development, Swift

Fun with print() in Swift

You use print() in Swift to print a string of text to the Console, or standard output. It’s super useful for debugging and finding out what’s going on in your code. In this tutorial, we’ll discuss how you can customize print() to code more productively.

Here’s what we’ll get into:

  • How do you use print() in Swift?
  • Working with #file, #function and #line literals
  • Customizing print()‘s separator and terminator
  • Printing a description of custom Swift objects

Ready? Let’s go.

  1. Writing Output with print()
  2. Print Line Number, Function and File
  3. Customizing print()’s Output
  4. How To Print Custom Objects
  5. Further Reading

Writing Output with print()

You use the print() function in Swift to write a string to standard output, which is typically the Console in Xcode. Here’s an example:

print("So long and thanks for all the fish!")

Example of print() in Xcode Playground

The above example can’t get any easier. We’re just printing a string of text to the Debug Area in an Xcode Playground.

Printing with print() works just about anywhere you code Swift:

  • When you’re debugging an app on your iPhone via Xcode, output from print() shows up in Xcode’s Console
  • It works in Xcode playgrounds, as we’ve seen in the above example
  • If you run code through the swift command line tool, output shows up in Terminal

What else can we do with print()?

Learn how to build iOS apps

Get started with iOS 14 and Swift 5

Sign up for my iOS development course, and learn how to build great iOS 14 apps with Swift 5 and Xcode 12.

You can use the special literals to print the file, function and line numbers of the print() statement. Here’s how:

print("\(#file):\(#function):\(#line) -- Hey!")
// Output: Print.playground:doSomething():5 -- Hey!

In the above code, we’re calling the print() function, which is part of a doSomething() function. The print() statement is on line no. 5 of the Print.playground file. Neat!

You can use the following literals with print():

  • #file for the filename
  • #function for the function name
  • #line for the line of the print() call

You can use these standalone, with something like print(#file), or as part of a string with \(···) string interpolation, like the above example. Making an informative string, like print("\(#function):\(#line)"), is super helpful in quickly printing where a certain print() has happened.

Which makes you wonder: When do you use all this stuff? Well, it’s no secret that many software developers use print() for poor man’s debugging. That is, sprinkling your code with a few print() statements to see what’s going on in there.

Like this:

let result = snowHeight > 5 && slopeIncline < 10 && reindeer == .active

if result {
    print("heyho ok this happend")
}

With the above hypothetical code, you can see with print() when the result expression is true. In other words, you can get a feel for the scenarios in which your app runs and gain a better understanding of the context of your code.

It would be better, of course, to use breakpoints and inspect values at runtime with po. But using print() statements has a certain quality and convenience to it that’s hard to describe. It’s imperfect, sure, but so are we software developers.

OK, back to #line and #function. You can improve your print() statements with those literals, especially if you’ve got a few of them. Check this out:

if snowHeight > 5 
{
    print("\(#function):\(#line) -- snow height ok")

    if slopeIncline < 10 
    {
        print("here ok ok")

        if reindeer == .active {
            print("\(#function):\(#line) -- reeindeer are good!")            
        }
    }
}

Ugly? Hell yes! Useful? You bet.

You can also use #column for the column number (i.e., character position from the left). It seems to indicate the starting position of the #column literal itself, which makes it less useful than #line for example.

Customizing print()’s Output

Even though we typically use the print statement as print(···), the function’s actual definition is this:

func print(_ items: Any..., separator: String = " ", terminator: String = "\n")

Whoah! Here’s what that means:

  • The print() function’s first unnamed parameter items has type Any, so you can pass any kind of value or reference to it.
  • See those 3 periods after Any? This means you can pass zero, one or more arguments into the print() function for that parameter.
  • The print() function has a separator parameter, a space symbol by default, which lets you separate multiple values with a custom character.
  • The same goes for the terminator, i.e. what comes at the end of the printed string. It’s a newline by default, but you can pick a custom character as well.

It’s important to keep in mind that print() will ultimately print a string. You can pass in any value, thanks to the Any type, but the print() function will (attempt to) convert that to a string.

When you pass a value into print(), that value is converted to a String value with the String(···) initializer. For most types this will print the value as a string. The String() initializer also looks for a description property, which is useful if you want to print custom objects.

Printing Multiple Values

OK, let’s check out a few examples. First, the basics:

let player1 = "Arthur"
let player2 = "Trillian"

print(player1, player2)
// Arthur Trillian

See how we’re providing the print() function with 2 parameters (or arguments, really)? This prints out the value of player1, a space symbol, the value of player2, and a newline \n symbol.

What’s the newline symbol for? This is added so that next time we use print(), it’s printed text is neatly added to a new line in the Console. You don’t see the newline character, but it’s there, much like the carriage return of a typewriter.

Custom Separator and Terminator

What about the separator parameter of print()? Check this out:

let data = [
    ["Jane", 99, "a", 2.0],
    ["John", 32, "z", 2.99],
    ["Jack", 13, "x", 1.34]
]

for item in data {
    print(item[0], item[1], item[2], item[3], separator: ";", terminator: ";\n")
}

The code produces the following output:

Jane;99;a;2.0;
John;32;z;2.99;
Jack;13;x;1.34;

Looks a bit like tabular comma-separated (CSV) data, right? In the code, we’ve printed out data from the data array. We’ve used multiple values for print(), and used custom strings for the separator and terminator parameters. Each item printed is separated with a semicolon, and the line ends with a semicolon and a newline. Neat!

Looking for a good example of print() to explain code, as it’s running? Check out the final implementation of binary search, in this tutorial: Play With Code: Binary Search In Swift

How To Print Custom Objects

You can also print your own custom structs, classes, etc. with print(). Take a look at the following struct:

struct Book {
    var title:String
    var author:String
    var pages:Int
}

let pigs = Book(title: "Animal Farm", author: "George Orwell", pages: 112)

When you do a print(pigs), you get the following output:

Book(title: "Animal Farm", author: "George Orwell", pages: 112)

This is a literal representation of the Book object. It contains too much information for it to be useful; we’d rather print something like the title and the author, for example. How?

First, make sure your custom type adopts the CustomStringConvertible protocol. Like this:

struct Book: CustomStringConvertible { ···

Then, add a computed property description to the struct, like this:

var description:String {
    return "\(title), \(author)"
}

The type of description is String, and the property returns a string. You can even omit the return keyword, if you want. In the above code, we’re returning a string that includes the title and author of the Book object.

Finally, we can print the object:

print(pigs)
// Output: Animal Farm, George Orwell

This way you can customize how a Swift object is printed out with print(). Awesome!

Learn how to build iOS apps

Get started with iOS 14 and Swift 5

Sign up for my iOS development course, and learn how to build great iOS 14 apps with Swift 5 and Xcode 12.

Further Reading

Working with print() was already useful, but thanks to things like #function and CustomStringConvertible now you can see what’s going on even better.

In this tutorial, we’ve discussed how you use print(), how to print multiple values, custom separators and terminators, how to print out custom objects, and more. Neat!

Want to learn more? Check out these resources:

Reinder de Vries

Hi, I'm Reinder.
I help developers play with code.

Get the Weekly

Get iOS/Swift tutorials and insights in your inbox, every Monday.
  • This field is for validation purposes and should be left unchanged.

Most Popular

Browse Topics

Swift Sandbox

Code Swift right in your browser!
Go to the Swift Sandbox

Reinder de Vries

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.

×

Build great iOS apps
Learn how in my free 7-day course

  • This field is for validation purposes and should be left unchanged.

No spam, ever. Unsubscribe anytime. Privacy Policy