Swift의 Closure
- Swift의 Closure를 다루기 전에 알아야하는 개념이 있다.
 - 바로 일급 객체라는 것이다.
 
일급 객체
- 
다음과 같은 조건을 만족하는 것을 일급 객체라고 할 수 있다.
- 변수나 데이터 구조안에 담을 수 있다.
 - 파라미터로 전달 할 수 있다.
 - 반환값(return value)으로 사용할 수 있다.
 - 할당에 사용된 이름과 관계없이 고유한 구별이 가능하다.
 - 동적으로 프로퍼티 할당이 가능하다.
 
 - 
우리가 Swift에서 알고 있는 대부분의 것은 일급 객체라고 할 수 있지만.
 - 
Method는 일급 객체가 아니고, Closure가 존재하는 이유이기도 하다.
 
Closure의 유형
- Closure의 유형은 3가지로 나눠볼수 있다.
- Global function
 - Nested function
 - Closure expressions
 
 
Global function
- Global function은 우리가 흔히 알고 있는 함수이다.
 - 클래스 밖의 함수라고 할 수 있다.
 
Nested function
- Nested function은 중첩 함수라고 말한다.
 - 함수 내부에서 다시 함수를 정의해서 사용하는 함수이다.
 - 외부에는 숨겨져 있고, 선언된 함수 내부에서만 호출이 가능하다.
 
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    
    return backward ? stepBackward : stepForward
}
Closure expressions
- 이것이 흔히 클로저라고 불리는 유형이다.
 - 문법은 다음과 같다.
 
{(parameters) -> return type in
    statements
}
클로저의 변수 할당
- 클로저는 일급 객체이기 때문에 변수에 할당될 수 있다.
 
let closureValue = { (name:String) in print(name) }
    
closureValue("hohyeonmoon")
- 또한, 함수의 인자 값으로 전달될 수 있다.
 
func closureOperation(then closure: () -> Void) {
	// Some code
}
클로저 축약하기
- Swift에서의 클로저는 다른 언어에서보다 유연하다.
 - 그래서 보다 자유롭게 축약하거나 변형할 수 있다.
 
// 이랬던 코드가
let string = "Hello, world!".transformWords(using: { word in
    return word.lowercased()
})
// 이렇게 축약된다
let string = "Hello, world!".transformWords { $0.lowercased() }
- 후행 클로저를 사용해 함수의 파라미터를 축약할 수 있다.
 - $0과 같은 인자 값을 사용해 첫 번째 인자값을 대체할 수 있다.
 - 단일 표현 클로저에서는 return 키워드를 생략할 수 있다.
 
Trailing Closures
- Trailing Closure로 마지막 파라미터 값으로 들어오는 Closure를 생략할 수 있다.
 
// 함수 선언
func someFunction (closure: () -> Void) {
	// Something
}
// 일반적인 함수 사용
someFunction (closure: {
    // Something
})
// Trailing Closure 사용
someFunction() {
    // Something
}
Capturing Values
- Closure는 주변의 value를 포착(capture)한다.
 - 다음 코드를 보자.
 
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    
    func incrementer() -> Int {
        runningTotal += amount
        
        return runningTotal
    }
    
    return incrementer
}
- incrementer 함수를 떼어놓고 보자.
 - 없는 runningTotal과 amount를 사용하고 있다.
 
func incrementer() -> Int {
    runningTotal += amount
    
    return runningTotal
}
- 그래서 주변 value를 capture 해서 사용한다.
 - 그래서 다음과 같이 코드를 반복 실행하면, 값이 계속 증가하게 된다.
 
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
Escaping Closure
- @escaping을 통해 escaping closure을 사용할 수 있다.
 - Escaping Closure는 기본값인 nonescape closure와 다른 점이 몇가지 있다.
 - 다음 코드와 같이 전달 받은 closure를 함수 외부에서 사용할 수 있다.
 
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
- 또, Escaping Closure는 함수가 종료된 뒤에도 메모리에 잡아둔다.
 - 그래서 비동기 프로그래밍을 할 때도 매우 유리하다.
 
