# Closure - 클로저는 정의된 컨텍스트에서 모든 상수와 변수에 대한 참조를 캡처하고 저장할 수 있습니다. #### 클로저 표현식 - 중첩 함수는, 더 큰 함수 안에서 그 자체로 동작하는 코드 블럭에 이름을 붙여 정의하는 편리한 수단이다. 하지만 더 짦은 버전의 함수구조를 완전한 선언과 이름 없이 작성하는게 유용할 때도 있습니다. - 이는 작업할 함수나 메소드가 자신의 인자로 함수를 입력 받을 때 특히 더 그렇습니다. ```swift let names = ["C", "A", "E", "B", "D"] func backward(_ s1:String, _ s2: String) -> Bool { return s1 > s2 } var reversedNames = names.sorted(by: backward) reversedNames -> ["E", "D", "C", "B", "A"] "B" 가 "A"보다 크다 라는 의미가 된다. A -> E 로 가려면 s1 < s2 가 되어야한다. ``` - 클로저 표현식 구문 ```swift {(parameters-매개 변수) -> return type-반환 타입 in statements-구문 } ``` 클로저 표현식 구문의 매개변수는 입-출력 매개 변수일 수 있지만, 기본 값이 있을 순 없습니다. 가변 매개 변수에 이름을 붙이면 가변 매개변수를 사용할 수 있습니다. 튜플을 매개 변수 타입과 반환타입으로 사용할 수도 있습니다. - 이전 예제를 클로저 표현식으로 변환 ```swift reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2}) ``` - 상황으로 타입 추론하기 - 정렬 클로저는 메서드에 인자로 전달되기 때문에, 이것의 매개 변수와 반환 값 타입을 스위프트가 추론할 수 있습니다. ->와 괄호도 생략이 가능하다. ```swift reversedNames = names.sorted(by: {s1, s2 in return s1 > s2 } ) ``` 단일 표현 `return`키워드를 생략할 수 있다. ```swift reversedNames = names.sorted(by: {s1, s2 in s1 > s2 }) ``` 하지만 더 간단하게 짧게 줄인 이름 - swift는 자동으로 인라인 클로저에 짧게 줄인 인자 이름을 제공하는데, 이를 쓰면 클로저 인자 값을 `$0`, `$1`, `$2` 등의 이름으로 참조할 수 있습니다. 이렇게하면 `in` 키워드도 생략할 수 있게된다. ```swift reversedNames = names.sorte(by: { $0 > $1 } ) ``` 여기서 $0 와 $1 은 클로저의 첫번째와 두번째 String 인수를 참조합니다. $1 이 짧은 인수에서 가장 높은 숫자이므로 클로저는 2개의 인수가 있다고 이해합니다. 여기서 sorted(by:) 함수는 인수가 모두 문자열인 클로저로 기대하므로 짧은 인수 $0 과 $1 은 모두 타입 String 입니다. - 연산자 메서드 - 더 짧게 표현도 가능합니다. 연산자를 활용하여 더욱 짧게 구현합니다. ```swift reversedNames = names.sorte(by: >) ``` ### 후행 클로저 - 함수의 마지막 인수로 함수에 클로저 표현식을 전달해야하고 클로저 표현식이 아주 길면 뒤에 딸린 클로저로 작성하는것이 유용할 수 있습니다. 뒤에 딸린 클로저는 함수 호출 괄호 뒤에 쓰는데, 그래도 뒤에 오는 클로저는 여전히 함수 인자입니다. - 일단 예제 코드 ```swift func someFunctionThatTakesAClosure(closure: () -> Void) { // 함수 본문은 여기에 둠 } // 뒤에 딸린 클로저를 쓰지 않고 이 함수를 호출하는 방법은 이렇습니다: someFunctionThatTakesAClosure(closure: { // 클로저 본문은 여기에 둠 }) // 뒤에 딸린 클로저를 써서 이 함수를 호출하는 방법은 이렇습니다: someFunctionThatTakesAClosure() { // 뒤에 딸린 클로저 본문은 여기에 둠 } ``` 앞에서 했던 문자열정렬 클로저 `sorted(by:)`메서드 괄호 밖에 뒤에 딸린 클로저로 쓸 수 있습니다. reversedNames = naes.sorted() { $0 > $1 } 클로저 표현식이 함수나 메서드에 제공된 유일한 인자인데 그 표현식을 뒤에 딸린 클로저로 제공하면, 함수를 호출할 때 함수나 메서드 이름 뒤에 한 쌍의 괄호() 를 쓸 필요가 없어집니다. ```swift reversedNames = names.sorted { $0 > $1 } ``` Swift의 Array 타입에는 클로저 표현식을 단일 인수로 사용하는 map(_:) 메소드가 있습니다. 클로저는 배열의 각 항목에 대해 한 번씩 호출되며 해당 항목에 대해 대체 매핑된 값(다른 유형일 수 있음)을 반환합니다. 매핑의 특성과 반환된 값의 형식은 map(_:)에 전달하는 클로저에 코드를 작성하여 지정합니다. 제공된 클로저를 각 배열 요소에 적용한 후 map(_:) 메서드는 원래 배열의 해당 값과 동일한 순서로 매핑된 새 값을 모두 포함하는 새 배열을 반환합니다. 후행 클로저와 함께 map(_:) 메서드를 사용하여 Int 값 배열을 String 값 배열로 변환하는 방법은 다음과 같습니다. 배열 [16, 58, 510]]은 새 배열 ["One Six", "Five ["OneSix", "FiveEight", "FiveOneZero"]를 만드는 데 사용됩니다. ```swift 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 배열을 사용하여 클로저 표현식을 배열 map(_:)메서드에 후행 클로저로 전달하여 `String`값의 배열을 만들 수 있다. ```swfit 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 is inferred to be of type [String] // its value is ["OneSix", "FiveEight", "FiveOneZero"] ``` 클로저의 입력 매개변수 `number`의 타입은 지정할 필요가 없습니다 왜냐 맵핑할 배열의 값으로 타입을 추론할 수 있기 때문입니다. `number` 변수를 클로저의 `number`매개 변수 값으로 초기화해서, 클로저 본문 안에서 값을 수정할 수 있습니다. 클로저 표현식은 `String`이라는 반환 타입을 지정하여, 맵핑된 출력 배열 안에 저장할 타입도 지시합니다. 클로저 표현식은 매 번 호출할 때마다 `output`이라는 문자열을 제작합니다 이는 나머지 연산자(number % 10)로 `number`의 마지막 숫자를 계산하고, 이 숫자로 `digitNames`딕셔너리에서 적절한 문자열을 찾습니다. 클로저를 사용하면 0보다 큰 어떤 정수라도 문자열로 나타낸 걸 생성할 수 있습니다. 딕셔너리에서 가져온 문자열을 output 앞에추가되며, 그 효과로 문자열 버전의 수를 역순으로 제작합니다 1의 자리수 부터 진행합니다! 그다음 10으로 나누기때문에 10의 자리를 표합니다. 이러한 과정을 반복하면 number가 0이 되는 순간 문자를 반환하고 종료 이러한 예제를 통해서 뒤에 딸린 클로저 구문을 사용하면 클로저가 지원할 함수 바로 뒤에 클로저 기능을 깔끔하게 감춰서 map메서드의 바깥쪽 괄호로 전체 클로저를 감쌀 필요가 없습니다.