[swift] 05. 클로저(Closure)
인라인 클로저 표현
{ (parameters) -> return type in
statements
}
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
추론
// 인자 타입 생략
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
// 단일 표현에서의 return keyword 생략
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
// 이름, in 생략
reversedNames = names.sorted(by: { $0 > $1 } )
// String 끼리의 비교는 비교 연산자 (>)가 사용 가능하므로 아래처럼 축약 가능
reversedNames = names.sorted(by: >)
후위 클로저 (Trailing Closure)
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// 마지막 인자인 경우, 인자값, 반환 값 생략 가능
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
reversedNames = names.sorted() { $0 > $1 }
// 마지막 인자가 클로저이고 인자가 없다면 후위 클로저를 사용할 수 있다.
reversedNames = names.sorted { $0 > $1 }
캡쳐
캡쳐한 값은 반환한 클로저의 생명주기와 같이한다. 새로이 생성될 때 캡쳐는 새로운 변수에 할당되고 이전에 생성한 클로저에는 영향을 주지 않는다.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// 값으로 10을 반환합니다.
incrementByTen()
// 값으로 20을 반환합니다.
incrementByTen()
// 값으로 30을 반환합니다.
// 새로운 함수를 생성하면,
let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// returns a value of 7 <- 이전 값 30에 영향을 받지 않는다.
incrementByTen()
// 값으로 40을 반환합니다. incrementBySeven 으로 생성한 값에 영향을 받지 않는다.
Escaping 클로저
클로저가 함수 밖에서 실행되는 경우 (비동기 처리 등)는 클로저 파라미터 앞에 @escaping이라는 키워드를 명시해야 한다. 이 때 escaping 클로저에서는 self를 명시적으로 언급해야 한다.
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
자동클로저 (Autoclosures)
인자 값이 없으며 특정 표현을 감싸서 다른 함수에 전달 인자로 사용할 수 있는 클로저.
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// Prints "5"
let customerProvider = { customersInLine.remove(at: 0) } // 자동 클로저
print(customersInLine.count)
// Prints "5"
print("Now serving \(customerProvider())!") // 자동 클로저 실행
// Prints "Now serving Chris!"
print(customersInLine.count)
// Prints "4"
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// Prints "Now serving Alex!"
// --> @autoclosure 사용
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0)) // @autoclosure 를 선언해서 { } 생략 가능