user678392 user678392 - 3 months ago 6
iOS Question

Don't understand closures example in Swift

I'm trying to learn about swift and closures.
I'm stuck on this example.

numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})


What is (number: Int) -> Int? Is it a function? Where is it defined?
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-ID1

What does the keyword "in" do? The docs say to use "to separate the arguments and return type from the body". I'm not sure I understand this. Why isn't "in" used to separate "let result = 3 * number" from "return result".

Answer

A closure is just a function with the parameters moved inside the brackets, with the keyword in to separate the parameters from the function body. The two following examples define equivalent functions:

func myFunc(number: Int) -> Int {
    let result = 3 * number
    return result
}

let myClosure = { (number: Int) -> Int in
    let result = 3 * number
    return result
}

You can actually call them both in exactly the same way:

let x = myFunc(2)       // x == 6
let y = myClosure(2)    // y == 6

Notice how the second example is exactly the same as the first, only in the first example, the parameters (number: Int) -> Int are outside the brackets, and in the second example the parameters are inside the brackets, followed by the keyword in.

map works by taking an array (numbers, in your example) and creating a new array that is the result of applying the closure function to each element in numbers. So if numbers is [1, 2, 3], the example above will start with 1. It will apply the closure function which will produce a 3 (cuz all it does is multiply the element from the first array by 3). It does that for each element in numbers, until it has produced a new array, [3, 6, 9].

If you wanted to, you could call map using the names of either the above function or the above closure, or by writing it out explicitly inside of map. All of the below examples are totally equivalent:

let numbers = [1, 2, 3]

// Example 1
let times3 = numbers.map(myFunc)        // times3 == [3, 6, 9]

// Example 2
let timesThree = numbers.map(myClosure) // timesThree == [3, 6, 9]

// Example 3
let xThree = numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result                       // xThree == [3, 6, 9]
})

Note that Example 3 is the same as Example 2, only in Example 3 the closure is spelled out explicitly inside of map, whereas in Example 2 the closure has been assigned to a constant called myClosure, and the constant has been supplied to map.

Hope this helps - closures are fun, but confusing.

Comments