클로저 (Closure)는 코드블럭으로 C와 Objective-C의 블럭(blocks)과 다른 언어의 람다(lambdas)와 비슷 합니다. 클로저는 어떤 상수나 변수의 참조를 캡쳐(capture)해 저장할 수 있습니다. Swift는 이 캡쳐와 관련된 모든 메모리를 알아서 처리 합니다.
캡처의 개념에 대해 익숙하지 않다고 걱정하지 않으셔도 됩니다. 값 캡쳐는 아래에서 자세히 설명해 두었습니다.
전역 함수(global functions)와 중첩 함수(nested function)은 실제 클로저의 특별한 경우 입니다. 클로저는 다음 세 가지 형태 중 하나를 갖습니다.
- 전역 함수: 이름이 있고 어떤 값도 캡쳐하지 않는 클로저
- 중첩 함수: 이름이 있고 관련된 함수로 부터 캡쳐할 수 있는 클로저
- 클로저 표현: 경량화 된 문법으로 쓰여지고 관련된 문맥(context)으로부터 값을 캡쳐할 수 있는 이름이 없는 클로저
Swift에서 클로저 표현은 최적화 되어서 간결하고 명확합니다. 이 최적화에는 다음과 같은 내용을. 포함합니다.
- 문맥(context)에서 인자 타입(parameter type)과 반환 타입(return type)의 추론
- 단일 표현 클로저에서의 암시적 반환
- 축약된 인자 이름
- 후위 클로저 문법
용어가 생소해 어렵게 느끼실 수 있지만, 하나하나 뜯어보면 어렵지 않고 쉽습니다.
클로저 표현(Closure Expressions)
클로저 표현은 인라인 클로저를 명확하게 표현하는 방법으로 문법에 초점이 맞춰져 있습니다. 클로저 표현은 코드의 명확성과 의도를 잃지 않으면서도 문법을 축약해 사용할 수 있는 다양한 문법의 최적화 방법을 제공 합니다.
정렬 메소드 (The Sorted Method)
Swift의 표준 라이브러리에 sorted(by:)
라는 알려진 타입의 배열 값을 정렬하는 메소드를 제공합니다. 여기 by
에 어떤 방법으로 정렬을 수행할 것인지에 대해 기술한 클로저를 넣으면 그 방법대로 정렬된 배열을 얻을 수 있습니다. sorted(by:)
메소드는 원본 배열은 변경하지 않습니다. 아래와 같이 이름으로 구성된 names
배열을 sorted(by:)
메소드와 클로저를 이용해 정렬해 보겠습니다.
sorted(by:)
메소드는 배열의 콘텐츠와 같은 타입을 갖고 두개의 인자를 갖는 클로저를 인자로 사용 합니다. name
의 콘텐츠는 String 타입이므로 (String, String) -> Bool
의 타입의 클로저를 사용해야 합니다.
클로저를 제공하는 일반적인 방법은 함수를 하나 만드는 것 입니다. 위 타입을 만족 시키는 함수를 하나 만들면 정렬에 인자로 넣을 수 있는 클로저를 만들 수 있습니다.
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedBanes = names.sorted(by: backward)
// Ewa, Daniella, Chris, Barry, Alex
클로저 표현 문법 (Closure Expression Syntax)
클로저 표현 문법은 일반적으로 아래의 형태를 띱니다.
{ (parameters) -> return type in statements}
}
인자로 넣을 parmeters
, 인자 값으로 처리할 내용을 기술하는 statements
그리고 return tyype
입니다. 앞의 backward
클로저를 이용해 배열을 정렬하는 코드는 클로저 표현을 이용해 다음과 같이 바꿀 수 있습니다.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
이렇게 함수로 따로 정의된 형태가 아닌 인자로 들어가 있는 형태의 클로저를 인라인 클로저
라 부릅니다.
클로저의 몸통(body)은 in
키워드 다음에 시작합니다. 사용할 인자 값과(parameters)반환 타입(return type)을 알았으니 이제 그것들을 적절히 처리해 넘겨 줄 수 있다는 뜻입니다. 클로저의 body
가 짧으니 아래와 같이 한줄에 적을 수 있습니다.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
문맥에서 타입 추론 (Inferring Type From Context)
위 예제에서 정렬 클로저는 String 배열에서 sorted(by:)
메소드의 인자로 사용됩니다.sorted(by:)
의 메소드에서 이미 (String, String) -> Bool
타입의 인자가 들어와야 하는지 알기 떄문에 클로저에서 이 타입들은 생략 될 수 있습니다. 그래서 위 함수는 더 생략한 형태로 아래와 같이 기술 할 수 있습니다.
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 })
위와 같이 클로저의 인자 값과 반환 타입을 생략할 수 있지만, 가독성과 코드의 모호성을 피하기 위해 타입을 명시할 수도 있습니다.
단일 표현 클로저에서의 암시적 반환 (Implicit Returns from Single-Express Closures)
단일 표현 클로저에서는 반환 키워드를 생략할 수 있습니다.
reverseNames = names.sorted(by: { s1, s2 in s1 > s2 })
이렇게 표현해도 어떠한 모호성도 없습니다. s1과 s2를 인자로 받아 그 두값을 비교한 결과를 반환 합니다.
인자 이름 축약 (Shorthand Arguments Names)
Swift는 인라인 클로저에 자동으로 축약 인자 이름을 제공 합니다. 이 인자를 사용하면 인자 값을 순서대로 $0, $1, $2 등으로 사용할 수 있습니다. 축약 인자 이름을 사용하면 인자 값과 그 인자로 처리할 때 사용하는 인자가 같다는 것을 알기 때문에 인자를 입력 받는 부분과 in
키워드 부분을 생략할 수 있습니다. 그러면 이런 형태로 축약 가능 합니다.
reversedNames = names.sorted(by: { $0 > $1 })
연산자 메소드 (Operator Methods)
축약을 더 할 수 있습니다. String
끼리 비교할 수 있는 비교 연산자(>) 구현.
reversedNames = names.sorted(by: >)
'iOS > Swift' 카테고리의 다른 글
Swift) UIkit 화면 이동 - FullScreen (0) | 2024.05.21 |
---|---|
Swift) Continuations 활용 (0) | 2024.05.20 |
콜렉션 타입(Collection Types) - 셋(Sets) (0) | 2023.04.21 |
콜렉션 타입(Collection Types) - Array (0) | 2023.04.19 |
Swift) 코드로 UITableView 구현하기 (0) | 2023.02.04 |