A function is simply a self-contained block of code that's given an identifiable name. You can then call these blocks of code, pass values into them, and even get values out of them. Closures are simply functions that can be passed around like any other type of object. They have the added ability to capture variables and constants from where they were declared, closing over them, and making those values available any time the closure is called.
At their most basic, a function can look like this:
func printGreeting() { print("Hello from a function") }
The keyword func
is used to declare the function's name and any code you want to run is contained within the braces {}
.
Calling the function is as easy as using the function name and adding a set of parentheses:
printGreeting()
There will be times that you would like to return a value from your function. Let's say you'd like to write a function that will always return you the Int
value of 9001:
func getValueOverNineThousand() -> Int { return 9001 }
You can declare a return value by adding the return arrow (->
) after the function name in the function's declaration, and then using the return
keyword to return the value you'd like inside the function.
When calling the function, you can now expect the return value to essentially replace the function call in your code:
let valueOverNineThouand = getValueOverNineThousand() In this example, thevalueOverNineThousand
constant will equal9001
. You can return multiple values from a function by using a tuple: func getBook() -> (title: String, author:String) { return ("Neuromancer", "William Gibson") }
When calling the function, it will return a tuple:
let book = getBook() //("Neuromancer", "William Gibson") let title = getBook().title // Neuromancer let author = getBook().1 // William Gibson
To let external factors affect the code inside a function, you can pass values into it by using parameters. You can pass as many or as few parameters as needed, you can make them optional and you can have them use default values.
To pass a single parameter, you add the name of the input parameter and the parameter type in the parentheses after the function name:
func printMessage(message:String) { print(message) }
The parameter message
is accessible from within the function and is simply printed out to the console.
If you'd like to add more parameters to the function, you simply need to separate them by a comma (,
):
func multiplyBy(num1:Int, num2:Int) { print(num1 * num2) }
This function multiplies two values together.
In the previous example, num1
and num2
are called internal parameter names. This simply means that these are the names that you will use to access the objects inside the function.
A goal of a developer should be to write clear, concise and self-documenting code. The code can be read easily and it is very clear in its purpose. To help with this goal, Swift lets you write external parameter names for each of your internal parameter names. These external names will be shown when using autocomplete in your editor and can save a lot of time and effort. For example, consider the following code:
func appendString(theString first: String, withString second: String) -> String { return "(first) (second)" }
first
and second
are internal names, while TheString
and withString
are external names. When you call the function, you have to then use these external names:
var strRes = appendString(theString: "Hello", withString: "World")
Adding an external parameter name to one parameter means that you're required to add them for all of your parameters. If you'd like to skip one or more external parameter names, you can simply use the wildcard symbol (_
) to do so:
func appendString(theString first: String, _ second: String) -> String { return "(first) (second)" }
Now the second external parameter name can be omitted:
var strRes = appendString(theString: "Hello", "World")
If you'd like to have a default value for one of your parameters, you can simply assign the value to the parameter when declaring the function:
func setVolume(valueWithDefault:Int = 11) { print("Volume is (valueWithDefault)") } setVolume() // Prints "Volume is 11" setVolume(1) // Prints "Volume is 1"
If no value is passed into the function, the default value is used.
One advanced feature is the ability to pass in variadic
parameters. These are parameters that accept zero or more values of a specific type. For example, let's write a function that lets us add an arbitrary number of integers together:
func add(numbers: Int...) -> Int { var result = 0 for number in numbers { result += number } return result } add(1, 2, 3, 4, 5, 6) // Returns 21
By writing three dots (...
) after the input parameter's type, you've declared that this is a variadic
parameter. Within the body, all of the values passed in are available to you as an array collection type (in this case, numbers
).
Swift lets you nest functions, letting you create reusable chunks of code only accessible inside a function:
func doSomeMaths(onNumber num:Int) -> Int { var scratchNumber = num func double(aNumber: Int) -> Int { return aNumber * 2 } return scratchNumber + double(9) } let result = doSomeMaths(onNumber: 100) // 118
The double
function is only available within the doSomeMaths
functional scope. See the Closures section for more information about scopes.
Functions in Swift have more advances features that fall outside the scope of this book such as: in-out parameters, constant and variable parameters, function types, and higher-order functions. Please see https://developer.apple.com/swift/resources/ for more information on these advanced topics.
Functions, as introduced earlier in this section, are actually a special kind of closure. Closures are simply a block of code that can be passed around and are similar to blocks in Objective-C or lamdas in other languages such as Java.
Think of them as functions that can be called later, from any scope, while still remembering the scope that they were declared in.
Scope is the term that describes what variables, constants, and functions are visible to any piece of code at one time. If you write two functions (they're said to be siblings) and declare variables in each one, they can't access each other's variables. A function can access the scope they are declared in (this scope is said to be its parent) and it's this scope that a closure remembers.
An example of a closure that prints "hello world"
to the console is as follows:
var printMessage: () -> () = { print("hello world") }
You can call this closure by calling the variable that was just declared:
printMessage()
If this looks familiar to you it's for a good reason: functions in Swift are simply special types of closures. The full syntax for a closure is as follows:
{ (parameters) -> return type in Statements }
If your closure doesn't return any values, you can omit the return type:
{ (parameters) in Statements }
Let's make a closure that takes someone's name (a parameter) and returns a greeting to that person:
var greetings: (String) -> (String) = { name in return "Hello (name)" } var greetingForDavid = greetings("David") // greetingForDavid equals "Hello David
The first set of parentheses declares the input parameters type, the return arrow lets you declare the return type, and the name
before the in
keyword declares the internal variable name accessible to the closure.
The closure greetings
that was just declared can be set as a value for a variable, it can be passed into a function as a parameter, and it can even be returned from a function.
As a final concept, let's talk about capturing values: a closure captures all of the variables from the scope where it was declared and makes them available from within the closure, no matter which scope the closure is being called from:
var number = 1 var doubleNumber= { // Trailing closure syntax number = number * 2 } func randomFunction() { doubleNumber() } doubleNumber() // number is 2 doubleNumber() // number is 4 randomFunction() // number is 8
The number
variable was declared in parent scope, the doubleNumber
closure always references the parental scope of number, even when it's being called from within a different function.
Closures are an advanced topic and have many more features that are outside the scope of this book. For more information, please see https://developer.apple.com/swift/resources/.
18.224.73.125