Updated for Xcode 14.2
When you want to return a single value from a function, you write an arrow and a data type before your function’s opening brace, like this:
func isUppercase(string: String) -> Bool {
string == string.uppercased()
}
That compares a string against the uppercased version of itself. If the string was already fully uppercased then nothing will have changed and the two strings will be identical, otherwise they will be different and ==
will send back false.
If you want to return two or more values from a function, you could use an array. For example, here’s one that sends back a user’s details:
func getUser() -> [String] {
["Taylor", "Swift"]
}
let user = getUser()
print("Name: \(user[0]) \(user[1])")
That’s problematic, because it’s hard to remember what user[0]
and user[1]
are, and if we ever adjust the data in that array then user[0]
and user[1]
could end up being something else or perhaps not existing at all.
We could use a dictionary instead, but that has its own problems:
func getUser() -> [String: String] {
[
"firstName": "Taylor",
"lastName": "Swift"
]
}
let user = getUser()
print("Name: \(user["firstName", default: "Anonymous"]) \(user["lastName", default: "Anonymous"])")
Yes, we’ve now given meaningful names to the various parts of our user data, but look at that call to print()
– even though we know both firstName
and lastName
will exist, we still need to provide default values just in case things aren’t what we expect.
Both of these solutions are pretty bad, but Swift has a solution in the form of tuples. Like arrays, dictionaries, and sets, tuples let us put multiple pieces of data into a single variable, but unlike those other options tuples have a fixed size and can have a variety of data types.
Here’s how our function looks when it returns a tuple:
func getUser() -> (firstName: String, lastName: String) {
(firstName: "Taylor", lastName: "Swift")
}
let user = getUser()
print("Name: \(user.firstName) \(user.lastName)")
Let’s break that down…
(firstName: String, lastName: String)
, which is a tuple containing two strings.firstName
is being set to “Taylor”, etc.getUser()
, we can read the tuple’s values using the key names: firstName
, lastName
, etc.I know tuples seem awfully similar to dictionaries, but they are different:
user["firstName"]
was going to be there, but Swift can’t be sure and so we need to provide a default value.user.firstName
: it’s not a string, so there’s also no chance of typos."firstName"
, but our tuple can’t – we must list all the values it will contain, and as a result it’s guaranteed to contain them all and nothing else.So, tuples have a key advantage over dictionaries: we specify exactly which values will exist and what types they have, whereas dictionaries may or may not contain the values we’re asking for.
There are three other things it’s important to know when using tuples.
First, if you’re returning a tuple from a function, Swift already knows the names you’re giving each item in the tuple, so you don’t need to repeat them when using return
. So, this code does the same thing as our previous tuple:
func getUser() -> (firstName: String, lastName: String) {
("Taylor", "Swift")
}
Second, sometimes you’ll find you’re given tuples where the elements don’t have names. When this happens you can access the tuple’s elements using numerical indices starting from 0, like this:
func getUser() -> (String, String) {
("Taylor", "Swift")
}
let user = getUser()
print("Name: \(user.0) \(user.1)")
These numerical indices are also available with tuples that have named elements, but I’ve always found using names preferable.
Finally, if a function returns a tuple you can actually pull the tuple apart into individual values if you want to.
To understand what I mean by that, first take a look at this code:
func getUser() -> (firstName: String, lastName: String) {
(firstName: "Taylor", lastName: "Swift")
}
let user = getUser()
let firstName = user.firstName
let lastName = user.lastName
print("Name: \(firstName) \(lastName)")
That goes back to the named version of getUser()
, and when the tuple comes out we’re copying the elements from there into individual contents before using them. There’s nothing new here; we’re just moving data around a bit.
However, rather than assigning the tuple to user
, then copying individual values out of there, we can skip the first step – we can pull apart the return value from getUser()
into two separate constants, like this:
let (firstName, lastName) = getUser()
print("Name: \(firstName) \(lastName)")
That syntax might hurt your head at first, but it’s really just shorthand for what we had before: convert the tuple of two elements that we get back from getUser()
into two separate constants.
In fact, if you don’t need all the values from the tuple you can go a step further by using _
to tell Swift to ignore that part of the tuple:
let (firstName, _) = getUser()
print("Name: \(firstName)")
SPONSORED From March 20th to 26th, you can join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer!
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.