Functions and closures

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

Returns

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.

Tip

You can return optionals from your functions. See the Optionals section for more information.

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, the valueOverNineThousand constant will equal 9001. 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

Note

See the Tuples section in this chapter for more information about this return type.

Parameters

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).

Note

You can only have one variadic parameter in a function and it needs to be the last parameter declared.

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.

Note

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.

Closures

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.

Note

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.

Note

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/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.73.125