클로져 트레일링
만약 여러분이 함수에 클로져 표현식을 함수의 마지막 인자로 전달하고 싶다면, 트레일링 클로져(trailing closure)를 사용하는 것이 좋습니다. 트레일링 클로져는 함수 호출의 소괄호 이후 부터 작성합니다. 소괄호를 벗어나지만 여전히 그 함수의 인자로 인정됩니다. 트레일링 클로져 문법을 사용할 때, 클로져에 인자 레이블을 부여해서는 안됩니다.
func someFunctionThatTakesAClousre(closure: () -> Void) {
// 실행할 함수 내부
}
// 트레일링 클로져 없이 함수를 호출 한다면?
someFunctionThatTakesAClosure(closure: {
// 실행할 클로져 내부
})
// 트레일링 클로져를 사용해 함수를 호출 한다면?
someFunctionThatTakesAClosure() {
// 실행할 클로져 내부
}
위 섹션에서 살펴본 문자열-정렬 클로져는 sorted(by:)
의 바깥에서 작성되었습니다. 이것 또한 트레일링 클로져입니다.
reversedNames = names.sorted() { $0 > $1 }
만약 클로져 표현식이 함수로 제공되거나 메서드의 유일한 함수로 제공된다면, 트레일링 클로져 앞의 소괄호 쌍 ()
을 작성하지 않아도 됩니다.
reversedNames = names.sorted { $0 > $1 }
트레일링 클로져는 클로져가 한 줄에 작성될 수 없을 정도로 길이가 길 때 유용합니다. 예를 들어, 스위프트의 Array
타입은 map(_:)
메서드를 가지고 있습니다. 이 메서드는 클로져 표현식을 유일한 인자로 받습니다. 이 클로져는 배열의 모든 아이템에 한 번씩 호출됩니다. 그리고 다른 매핑된 값을 반환합니다. 매핑의 특성과 반환되는 값의 타입은 클로져가 정하게 됩니다.
모든 배열의 원소에 클로져를 적용하고 나면, map(_:)
메서드는 매핑된 값들을 포함한 새로운 배열을 반환합니다. 이 때, 원본 배열과 똑같은 순서가 유지 됩니다.
어떻게 map(_:)
함수를 트레일링 클로져와 사용하여 Int
배열을 String
배열로 바꾸는지 작성해보겠습니다. 배열 [16, 58, 510]
은 ["OneSix", "FiveEight", "FiveOneZero"]
으로 반환됩니다.
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]
이 코드는 영어 버젼의 숫자와 그 숫자에 대한 딕셔너리를 생성합니다. 또한 정수의 배열을 정의하였습니다. 이제 문자열로 변환할 준비를 마쳤습니다.
여러분은 이제 numbers
배열을 String
값의 배열로 생성할 수 있습니다. 클로져 표현식을 배열의 map(_:)
메서드의 트레일링 클로져로 전달합니다.
let strings = numbers.map { (number) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
// strings는 [String] 타입으로 추론됩니다.
// 이 상수의 값은 ["OneSix", "FiveEight", "FiveOneZero"] 입니다.
클로져 표현식을 호출한 것은 map(_:)
메서드입니다. 이 클로져 표현식은 배열의 모든 아이템을 한 번씩 호출합니다. 클로져의 입력 파라미터에 타입을 명시할 필요는 없습니다. 왜냐하면 이 타입, number
의 타입은 배열의 값으로부터 추론될 수 있기 때문입니다.
예를 들어, 변수 number
는 클로져의 number
파라미터의 값으로 초기화됩니다. 따라서, 값은 클로져 내부에서 수정됩니다. 클로져 표현식은 또한 반환 타입인 String
을 추론합니다.
클로져 표현식은 배열의 원소를 한 번씩 호출할 때 마다, output
이라는 문자열을 만듭니다. 이것은 number
의 마지막 숫자를 나머지 연산자 (number % 10
)으로 계산하며, 이 값은 digitNames
딕셔너리의 적절한 문자열을 찾는데 사용됩니다. 이 클로져는 0보다 큰 어떠한 정수라도 문자열 표현을 만들 수 있습니다.
주의
이 예제에서,
digitNames
딕셔너리의 서브스크립트 뒤에 느낌표 (!
) 가 사용되었습니다. 왜냐하면 딕셔너리의 서브스크립트는 옵셔널 값을 반환하여 딕셔너리가 키를 찾지 못할 때를 알려주기 위해서 입니다.number % 10
은 항상digitNames
딕셔너리의 적절한 서브스크립트 키를 가져오는 것이 자명하므로, 강제 언래핑인 느낌표(!
)를 사용하였습니다.
이 딕셔너리, digitNames
에서 꺼내온 문자열은 output
의 앞에 추가됩니다. 숫자를 거꾸로 추가하여 문자열 버젼으로 만들기 위해서 입니다. ( number % 10
은 16
에는 6
을 반환, 58
에는 8
, 510
에는 0
을 반환 )
이후, 변수 number
는 10
으로 나누어 집니다. 왜냐하면 이것은 정수이므로 소수점 이하는 버려지게 됩니다. 따라서 16
은 1
이 되고, 58
은 5
가 되며, 510
은 51
이 됩니다.
이 절차는 number
가 0이 될 때 까지 반복됩니다. 그리고 output
문자열이 클로져에 의해 반환되며 map(_:)
메서드가 반환할 배열에 추가됩니다.
트레일링 클로져 문법을 사용하면 간결하게 클로져의 기능을 캡슐화할 수 있습니다. 따라서, map(_:)
메서드의 소괄호 내에 클로져 전체를 감쌀 필요가 없습니다.
원본 : https://docs.swift.org/swift-book/LanguageGuide/Closures.html
'Swift > Swift Language' 카테고리의 다른 글
Swift 언어 가이드 - 클로져는 참조 타입이다 (0) | 2020.03.08 |
---|---|
Swift 언어 가이드 - 값 캡쳐링 (0) | 2020.03.06 |
Swift 언어 가이드 - 클로져 기본 (0) | 2020.03.05 |
Swift 언어 가이드 - 클로져 표현식 (0) | 2020.02.22 |
Swift 언어 가이드 - 함수 (0) | 2020.02.18 |