Swift - Function and Closures
Published: 2022-04-03 13:06:42

## Function
- A Function can have 0 parameter to multiple parameter.
- A Function can have 0 return value(void) or multiple return value(using tuple) or even optional as return value.
- Each function parameter has both an argument label and a parameter name. By default, parameters use their parameter name as their argument label if argument label  is not provided.
- If you don’t want an argument label for a parameter, write an underscore (_) instead 
- You can define a default value for any parameter in a function by assigning a value to the parameter after that parameter’s type. If a default value is defined, you can omit that parameter when calling the function.

example : 

``` swift
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
    print("someFunction")
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) 
someFunction(parameterWithoutDefault: 4) 
```

- A **variadic** parameter (...) accepts zero or more values of a specified type. he values passed to a variadic parameter are made available within the function’s body as an array.

**The first parameter that comes after a variadic parameter must have an argument label to avoid ambiguity.**

example : 

``` swift
func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
```

- Define that parameter as an in-out parameter if  you want a function to modify a parameter’s value, because function parameters are constants by default. place an ampersand (&) directly before a variable’s name while passing a value to inout parameter.

**In-out parameters can’t have default values, and variadic parameters can’t be marked as inout.**

example : 

``` swift
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
```

- Use function types just like any other types.

example : 

``` swift
func addTwoInts(_ a: Int, _ b: Int) -> Int {
    return a + b
}
var mathFunction: (Int, Int) -> Int = addTwoInts
```

- Function Types can be used as a Parameter Types or Return types

---

## Closures
Closures are self-contained blocks of functionality that can be passed around and used in your code. **Closures can capture and store references to any constants and variables from the context in which they’re defined.**

- Closures take one of three forms:

1. Global functions are closures that have a name and don’t capture any values.
2. Nested functions are closures that have a name and can capture values from their enclosing function.
3. Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

### Closure Expressions

syntax : 

```
{ (parameters) -> return type in
    statements
}
```

example : 

``` swift
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})
```

- shorthand closure syntax
   Inferring parameter and return value types from context. 
   Implicit returns from single-expression closures.
    example : 
    

``` swift
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
```
- shorthand argument names

example : 
    

``` swift
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
```
- **Trailing closure** - a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead.

example : 
    
``` swift
reversedNames = names.sorted() { $0 > $1 }
```

If a closure expression is provided as the function’s or method’s only argument , parentheses () can be omitted.

``` swift
reversedNames = names.sorted { $0 > $1 }
```

Closures and Functions Are Reference Types. Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure.

### Escaping Closure
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. write **@escaping** before the parameter’s type to indicate that the closure is allowed to escape.

example : 

``` swift
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
```

### Autoclosure

- An autoclosure is a closure that’s automatically created to wrap an expression that’s being passed as an argument to a function. 
- It doesn’t take any arguments, and when it’s called, it returns the value of the expression that’s wrapped inside of it.

example :
**without autoclosure :**

``` swift
var customersInLine = ["Chris", "Alex", "Ewa","Barry"]
func serve(customer customerProvider: () -> String) {
    print("Now serving \(customerProvider())!") ////"Now serving Chris!"
}
serve(customer: { customersInLine.remove(at: 0) } )
```

**with autoclosure :**

``` swift
var customersInLine = ["Chris", "Alex", "Ewa", "Barry"]
func serve(customer customerProvider: @autoclosure () -> String) {
    print("Now serving \(customerProvider())!") ////"Now serving Chris!"
}
serve(customer: customersInLine.remove(at: 0))
```