-
Swift 5.6 Closures기술/iOS 2022. 3. 20. 17:43
Closures
클로저는 정의된 컨텍스트에서 모든 상수와 변수에 대한 참조를 캡처하고 저장할 수 있습니다. 이러한 상수와 변수를 폐쇠라고 합니다.
함수에서 소개한 전역과 중첩함수는 클로저의 특별한 케이스입니다. 클로저는 3가지 형태 중 하나를 취합니다.
- 전역함수는 이름을 가지고 어떠한 값도 캡처하지 않는 클로저입니다.
- 중첩함수는 이름을 가지고 둘러싼 함수로부터 값을 캡처할 수 있는 클로저입니다.
- 클로저 표현식은 주변 컨텍스트에서 값을 캡처할 수 있는 경량 구문으로 작성된 이름 없는 클로저입니다.
Swift 에서 클로저 표현식은 일반 시나리오에서 간단하고 깔끔한 구문을 장려하는 최적화를 통해 깔끔하고 명료한 스타일을 가지고 있습니다.
- 컨텍스트에서 파라미터와 반환값 유추
- 단일 표현식 클로저 암시적 반환
- 약식 인자 이름
- 후행 클로저 구문
Closure Expressions
클로저 표현식은 간단하고 집중적인 구문으로 인라인 클로저로 작성하는 방법입니다. 클로저 표현식은 명확성이나 의도를 잃지 않고 짧은 형태로 클로저를 작성하기 위한 몇가지 구문 최적화를 가지고 있습니다. 각 예제는 동일한 기능을 보다 간결한 방식으로 표현합니다.
The Sorted Method
Swift 의 표준 라이브러리를 사용자가 제공하는 정렬 클로저의 출력을 기반으로 알려진 타입의 값을 정렬하는 sorted(by:) 라는 메서드를 제공합니다.
이 예제는 String 값의 배열을 정렬하고 정렬 클로저는 (String, String) -> Bool 타입의 함수를 필요로 합니다.
정렬 클로저를 제공하는 한 가지 방법은 올바른 타입의 일반 함수를 작성하고 메서드에 인자로 전달하는 것입니다.
func backward(_ s1: String, _ s2: String) -> Bool { return s1 > s2 } var reversedNames = names.sorted(by: backward) // reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
Closure Expression Syntax
클로저 표현구는 아래와 같은 일반적인 형태를 가지고 있습니다
클로저 표현구 파라미터는 in-out 파라미터일 수 있지만 기본 값을 가질 수 없습니다. 가변 파라미터를 사용할 수 있습니다. 튜플은 파라미터 타입과 반환 타입으로 사용할 수 있습니다.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 })
클로저의 바디의 시작은 in 키워드로 시작합니다. 이 키워드는 클로저의 파라미터와 리턴 타입 정의가 끝남을 나타내며 클로저의 바디가 시작함을 나타냅니다.
바디가 너무 짧기 때문에 한 줄로 작성할 수 있습니다.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
Inferring Type From Context
정렬 클로저는 메서드에 인자로 전달되기 때문에 Swift 파라미터 타입과 반환되는 값의 타입을 유추할 수 있습니다. 즉, 클로저 표현식 정의에 일부러 작성할 필요가 없음을 의미합니다.
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
함수나 메서드에 클로저를 인라인 클로저 표현식으로 전달할 때 항상 파라미터 타입과 반환 타입을 유추할 수 있습니다. 결과적으로 클로저가 함수 또는 메서드 인자로 사용될 때 완전한 형태로 인라인 클로저를 작성할 필요가 없습니다.
Implict Returns from Single-Expression Closures
단일 표현 클로저는 이전 예제에서 return 키워드를 생략하여 단일 표현식을 암시적으로 반환할 수 있습니다.
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
Shorthand Argument Names
Swift 는 인라인 클로저에 $0 , $1 등 클로저의 인자값으로 참조하는데 사용할 수 있는 자동적으로 생성된 짧은 인자 이름을 제공합니다.
클로저 표현식에 이런 짧은 인자 이름을 사용한다면 선언에 클로저의 인자 목록을 생략할 수 있고 인자의 이름의 수와 타입은 함수 타입에서 유추됩니다. 클로저 표현식이 전체 바디로 구성되기 때문에 in 키워드를 생략할 수도 있습니다.
reversedNames = names.sorted(by: { $0 > $1 } )
Operator Methods
여기서 더 짧게 작성하는 방법이 있습니다. Swift 의 String 타입은 보다 큰 연산자의 문자열 별 구현을 String 타입의 파라미터 2개가 있는 메서드로 정의하고 Bool 타입을 반환합니다. 이것은 sorted(by:) 메서드에 필요한 메서드 타입과 정확히 일치합니다. 따라서 간단하게 보다 큰 연산자를 전달할 수 있고 Swift 는 문자열 특정 구현을 사용하기 원한다고 유추합니다.
reversedNames = names.sorted(by: >)
Trailing Closures
함수 마지막 인자로 함수에 클로저 표현식을 전달해야하고 클로저 표현식이 긴 경우 후행 클로저로 작성하는 것이 유용할 수 있습니다. 후행 클로저는 함수의 인자이지만 함수 호출의 소괄호 다음 작성합니다. 후행 클로저 구문을 사용할 때 함수 호출의 일부로 첫번째 클로저 인자 라벨을 작성하지 않아도 됩니다. 함수 호출은 여러개의 후행 클로저를 포함할 수 있지만 아래 몇가지 예제에서는 단일 후행 클로저를 사용합니다.
reversedNames = names.sorted() { $0 > $1 }
유일한 인자인 경우 소괄호를 작성하지 않아도 됩니다.
reversedNames = names.sorted { $0 > $1 }
후행 클로저는 길어서 한줄로 인라인 작성이 불가능할 때 유용합니다.
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"]
함수가 여러개의 클로저를 가지고 있다면 첫번째 후행 클로저의 인자 라벨은 생략하고 남은 후행 클로저 라벨은 표기합니다.
func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void) { if let picture = download("photo.jpg", from: server) { completion(picture) } else { onFailure() } } loadPicture(from: someServer) { picture in someView.currentPicture = picture } onFailure: { print("Couldn't download the next picture.") }
Capturing Values
클로저는 정의된 둘러싸인 컨텍스트에서 상수와 변수를 캡처할 수 있습니다. 그러면 클로저는 상수와 변수를 정의한 원래 범위가 더 이상 존재하지 않더라도 바디 내에서 해당 상수와 변수를 참조하고 수정할 수 있습니다.
? Closures are Reference Types
뭘 이야기하고 싶었던 걸까?
? Escaping Closures
어떻게 정의하고 설명해야할지 모르겠다
내가 아는건 함수 반환 후 실행된다는 것 까지
? Auto Closures
자동 클로저는 함수에 인자로 전달되는 표현식을 래핑하기 위해 자동으로 생성되는 클로저 입니다. 인자를 가지지 않으며 호출될 때 내부에 래핑된 표현식의 값을 반환합니다. 이러한 구문상의 편의를 통해 명시적 클로저 대신 일반 표현식을 작성하여 함수의 파라미터 주위의 중괄호를 없앨 수 있습니다.
자동 클로저를 가지는 함수를 호출하는 것은 일반적이지만 이러한 함수를 구현하는 것은 일반적이지 않습니다.
클로저가 호출될 때까지 코드 내부 실행이 되지 않기 때문에 자동 클로저는 판단을 지연시킬 수 있습니다. 판단 지연은 코드 판단 시기를 제어할 수 있기 때문에 사이드 이펙트가 있거나 계산이 오래 걸리는 코드에 유용합니다.
어떻게 쓰라는 걸까?
'기술 > iOS' 카테고리의 다른 글
Swift 5.6 Structures and Classes (0) 2022.03.20 Swift 5.6 Enumerations (0) 2022.03.20 Swift 5.6 Functions (0) 2022.03.20 Swift 5.6 Control Flow (0) 2022.02.26 Swift 5.6 Arrays (0) 2022.02.26