Back to blog

Fun with print() in Swift


Aasif Khan
By Aasif Khan | Last Updated on January 10th, 2024 3:32 pm | 6-min read

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 mobile app development 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
  • print()‘s separator and terminator
  • Printing a description of custom Swift objects

Describe your app idea
and AI will build your App

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!”)

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

Now, you might be wondering, why is the print() function so essential? Well, it’s one of the simplest tools developers have to see the immediate results of their code. Think of it as a small window into your program’s world.

Whenever you’re unsure about a value or want to check if a particular piece of code runs, print() comes to the rescue.

For beginners, here’s a quick tip: If you’re ever lost or unsure about what a piece of code is doing, sprinkle in a few print() statements. It’s like leaving breadcrumbs for yourself. You can trace how your code is behaving by checking the messages you’ve printed out.

For instance, if you’re working with loops and want to see how many times it’s running, you can do something like this:

for i in 1…5 {
print(“This is loop number \(i)”)
}

When you run this, you’ll see a series of messages in your console, each indicating the loop’s current iteration. It’s a simple yet effective way to understand what’s happening under the hood.

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()?

Print Line Number, Function and File

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!

For those who are new to Swift or programming in general, you might be wondering, “Why would I want to print the file, function, or line number?” Well, these literals are incredibly handy when debugging.

Imagine you have a large project with multiple files and functions. If something goes wrong or behaves unexpectedly, it can be like finding a needle in a haystack. By using these literals, you can quickly pinpoint where a particular message or value is coming from.

Let’s break it down a bit:

  • #file: This gives you the name of the file where the print() statement is located. Especially useful if you have many Swift files in your project.
  • #function: This tells you the name of the function or method containing the print() statement. It’s a quick way to know which part of your code is sending a message.
  • #line: This provides the exact line number of the print() statement within its file. If you’re trying to track down an elusive bug, knowing the exact line can be a lifesaver.

Here’s a practical scenario: Suppose you have a function that’s supposed to be called only once, but you suspect it’s being called multiple times. You can add a print() with these literals to confirm your suspicion:

func fetchData() {
print(“Fetching data from \(#function) in \(#file) at line \(#line)”)
// Rest of the function code
}

When you run your app, if you see this message more than once, you’ll know there’s an issue, and you’ll know exactly where to look.

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.

Let’s dive a bit deeper into the customization options of the print() function, especially for those who are just starting out with Swift:

  • Separator: The separator is what goes between the items you’re printing. By default, it’s a space. So, if you print multiple items, they’ll be spaced out. But what if you wanted something else, like a dash or a comma? That’s where the separator comes in. For example:

    print(“Hello”, “World”, separator: “-“)
    This will output: Hello-World.

  • Terminator: After the print() function has printed all the items, it adds a terminator. By default, this is a newline (\n), which means any subsequent print() calls will start on a new line. But sometimes, you might want to continue on the same line or add a different ending. Here’s how:

    print(“Hello”, terminator: “…”)
    print(“World”)

    This will output: Hello…World.

  • Printing Multiple Items: The beauty of the print() function is its flexibility. You’re not limited to printing just one item. You can print multiple items, and they’ll be separated by the separator you’ve specified (or a space by default). For instance:

    print(“Name:”, “John”, “Age:”, 30)

    This will output: Name: John Age: 30.

Understanding these customization options can greatly enhance the way you display information in the console, making it more readable and structured, especially when debugging or showcasing results.

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!

Conclusion

The print() function in Swift is a versatile tool that every developer, whether beginner or seasoned, should be familiar with. It offers a simple yet effective way to debug, understand, and showcase the behavior of your code.

From basic string outputs to advanced customizations using separators, terminators, and special literals, print() provides a range of functionalities to make coding more productive. As you continue your journey in Swift, remember to utilize this function to gain insights into your code’s operations, making the development process smoother and more efficient.


Aasif Khan

Head of SEO at Appy Pie

App Builder

Most Popular Posts