Closures #3
Trailing Closures(후행 Closures)
- 길이가 긴 closure 표현식을 함수의 마지막 인자로 전달하고자 할 경우 trailing closure를 사용하는 것이 더 유용하다.
- 함수의 파라미터이지만 trailing closure는 파라피터가 포함된 괄호 밖에 쓴다.
- trailing closure 문법을 사용할 경우 첫 번째 closure에 대한 argument label을 적을 필요가 없다.
- 함수 호출 시 여러개의 trailing closure를 포함할 수 있다.
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body
}
someFunctionThatTakesAClosure(closure: {
// closure's body
})
someFunctionThatTakesAClosure() {
// trailing closure's
}
- 앞서
sorted(by:)
메서드의 예제는 다음과 같이 trailing closure로 쓸 수 있다.
reversedNames = names.sorted() {$0 > $1}
- 만일 closure 표현식이 함수나 메서드의 유일한 인자로 전달되고 trailing closure라면 함수나 메서드 이름 뒤의 괄호를 생략할 수 있다.
reverseNames = names.sorted { $0 > $1 }
- trailing closure는 closure가 한 문장의 inline 표현식으로 사용되지 못할만큼 긴 경우 유용하다.
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map { (number) -> String in // 파라미터로 trailing closure 전달
var number = number
var output = ""
repeat {
// 딕셔너리 검색 시 키가 없는 경우 nil이 반화될 수 있기 때문에 딕셔너리의 원소 값은 옵셔널로
// 반환된다. 하지만 이 코드에서는 키 값이 반드시 존재하는 상황이어서 force-unwrap하고 있음
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
- 위의 코드는 Swift의 Array에 있는
map(_:)
함수에 대한 예이다.map(_:)
함수는 하나의 closure 표현식을 인자로 받는다.- closure는 배열의 각 item마다 한번씩 호출되며 인자로 전달된 아이템에 대한 값을 반환한다(type은 다를 수도 있다).
- 인자로 전달된 closure의 코드를 작성하여 mapping의 특성과 반환 type을 지정할 수 있다.
- closure가 배열의 모든 요소에 대해 작업을 완료하면
map(_:)
함수는 원래 배열의 값과 대응되며 동일한 수서를 갖는 새로운 배열을 반환한다. - 매핑될 배열로부터 type이 자동 추론되므로 closure에 파라미터 type을 명시할 필요는 없다.
- 위 예제와 같이 trailing closure는 함수의 괄호로 둘러쌀 필요가 없다.
- 함수가 여러개의 trailing closure를 취하는 경우 함수 호출 시 첫 번째 trailing closure는 argument label을 생략할 수 있고 나머지 trailing closure에는 label을 붙여야 한다.
func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void) {
if let picture == download("photo.jpg", from: server) {
completion(picture)
} else {
onFaliure()
}
}
- 위 함수를 호출할 때 2개의 closure를 넘겨야 한다. 하나는 completion handler로 다운로드가 성공한 후 사진을 보여주는 closure이고, 다른 하나는 error handler로 사용자에게 error 내용을 보여준다.
loadPicture (from: someServer) { picture in // 첫 번째 closure는 argument label 생략
someView.currentPicture = picture
} onFailure: { // 두 번째 closure는 argument label 사용
print("Couldn't download the next picture.")
}