- Write and call functions with parameters and return values
- Use argument labels,
_and default parameter values - Write closures, shorten them and recognise trailing closure syntax
Imagine you calculate a ticket price in ten different places in your app. When the rules change, you have to fix ten places — and you will surely forget one. The answer is a function: you write the code once, give it a name and call it wherever you need it. You have already used ready-made functions such as print, sorted() and map — now you will write your own.
Declaring a function
A function starts with the keyword func. The parameters are written in parentheses together with their types, and the type of the returned value comes after ->. return sends the result back. If the body of the function is a single expression, you can leave out the word return.
func greet(name: String) -> String {
return "Hello, \(name)!"
}
func square(_ x: Int) -> Int {
x * x
}
print(greet(name: "Aysel"))
print(square(7))
print(square(square(2)))Hello, Aysel! 49 16
Argument labels and default values
In Swift every parameter can have two names, so that a call reads like a sentence: an argument label (written when calling) and a parameter name (used inside the function). The function travel(from start: String, to end: String) is called as travel(from: "Baku", to: "Shaki"). If you don't want a label, write _ instead — that is exactly how square(7) works.
A parameter can have a default value: if you leave it out when calling, that value is used. Below, a ticket costs 5 manat for children under 12, 7.5 manat for students and 10 manat for everyone else.
func travel(from start: String, to end: String) {
print("Travelling from \(start) to \(end)")
}
func ticketPrice(for age: Int, isStudent: Bool = false) -> Double {
if age < 12 {
return 5.0
} else if isStudent {
return 7.5
}
return 10.0
}
travel(from: "Baku", to: "Shaki")
print(ticketPrice(for: 8))
print(ticketPrice(for: 20))
print(ticketPrice(for: 20, isStudent: true))Travelling from Baku to Shaki 5.0 10.0 7.5
Closures
A block of code without a name that can be stored in a variable and passed to another function. It is written in curly braces: first the parameters and return type, then the word in, then the body.
Swift lets you shorten closures step by step: it infers the types from the context, does not require return for a single expression and lets you refer to the parameters as $0 and $1. Below, the same sort is written four times, each one shorter:
let double = { (x: Int) -> Int in
return x * 2
}
print(double(5))
let numbers = [5, 2, 9, 1]
print(numbers.sorted(by: { (a: Int, b: Int) -> Bool in
return a > b
}))
print(numbers.sorted(by: { a, b in a > b }))
print(numbers.sorted { $0 > $1 })
print(numbers.sorted(by: >))10 [9, 5, 2, 1] [9, 5, 2, 1] [9, 5, 2, 1] [9, 5, 2, 1]
Trailing closures
If a closure is the last argument of a function, you can write it after the parentheses — this is called a trailing closure. numbers.sorted { $0 > $1 } and prices.map { $0 * 2 } are written exactly like that. You can also write your own function that takes a closure; its parameter has a function type such as () -> Void.
func repeatTask(times: Int, task: () -> Void) {
for _ in 1...times {
task()
}
}
repeatTask(times: 3) {
print("Hip hip hooray!")
}
func apply(_ value: Int, _ operation: (Int) -> Int) -> Int {
operation(value)
}
func triple(_ x: Int) -> Int {
x * 3
}
print(apply(4) { $0 + 10 })
print(apply(4, triple))Hip hip hooray! Hip hip hooray! Hip hip hooray! 14 12
Closures remember the variables around the place where they were created (this is called capturing). The makeCounter below returns a counter that grows by one on every call: the variable count keeps living inside the closure even after the function has finished.
func makeCounter() -> () -> Int {
var count = 0
return {
count += 1
return count
}
}
let counter = makeCounter()
print(counter())
print(counter())
print(counter())1 2 3
Key points
- A function is declared as
func name(parameter: Type) -> ReturnType { ... }. - The argument label is used in the call and the parameter name inside the function;
_removes the label. - A parameter with a default value can be left out of the call.
- A closure is an unnamed function;
$0and$1are its parameters. - A closure that is the last argument can go after the parentheses; closures remember the variables around them.
Check yourself
10 questions. Every correct answer earns XP.
func travel(from start: String, to end: String)?