2014.08.12 11:21

Swift - Closures


Closures

클로져는 사용자 코드에서 다른 코드나 함수로 전달 될 수도 있고, 또 그 자체가 사용되어 질 수 있는 기능에 대한 자립적인 블럭을 말한다.

또한, 클로저에는 클로저가 정의된 곳의 context로 부터 상수나 변수에 대한 reference를 수집(capture)하거나 저장(store) 가능한데 이를 두고 변수나 상수를 closing한다라는 표현을 사용하기에 closures라는 이름으로 불린다.


reference capturing 에 대한 부분은 별도로 설명하고 있으나 간략하게 정리하면, 클로저가 해당 변수나 상수를 지속적으로 참고하고 있으며, 변수일 경우 해당 정보의 변경에 대한 정보를 지속적으로 얻을 수 있는 것을 말한다.


Global 함수와 nested 함수가 closure에 대한 특별한 모습이라 할 수 있으며, 클로져는 다음 세 가지 중 하나의 모습을 갖게 된다.

  • Global 함수는 이름을 갖고 어떠한 값도 수집하지 않는 클로져이다
  • Nested 함수는 이름을 가지고 해당 함수를 포함하는 함수의 값을 수집 할 수 있는 클로져이다
  • 클로져 expression은 이름이 없는 클로져로, 해당 클로져를 포함하는 context의 값을 수집 할 수 있도록 간략한 형태이다

Closures Expressions

Closure Expressions은 syntax를 중점으로 inline closure를 간략하게 작성하는 방법을 말한다.
Closure Expressions은 명료함과 의도에 대한 손실 없이 클로저를 가장 단순화 할 수 있는 몇몇의 최적화 syntax를 제공한다.

Closure Expression을 잘 설명하기 위해 sorted 함수를 먼저 소개를 한다.
  • The Sorted Function
    • Swift 표준 라이브러리에는 sorted라는 이름의 함수를 제공한다
    • 이는 프로그래머가 제공한 클로저 함수의 결과를 기준으로 주어진 타입의 Array의 값을 정렬 해 주는 함수이다.
    • 호출이 완료되면 sorted 함수는 기존 입력했던 Array와 동일한 타입과 크기의 정렬된 array를 생성하며 원본은 변하지 않는다.
    • sorted 함수는 다음 두 가지 정보를 argument로 입력 받는다
      • 알고 있는 타입 값의 Array
      • Array 에 담고 있는 값의 타입과 동일한 타입 두 개를 argument로 그리고 리턴 타입으로 앞서 입력 받은 타입을 비교하여 그 결과에 대해 true 또는 false를 리터하는 클로저 타입
    • 예를 들어 문자열 Arrary라면 다음과 같다
      • let names = ["Hello", "World", "Swift", "Programming"]
    • 이럴 경우 클로져 타입은 (String, String) -> Bool 이 되고
      • func backwards(s1: String, s2: String) -> Bool {
      •   return s1 > s2
      • }
      • var reversed = sorted(names, backwards)

이제 Closure Expression 에 대해 자세히 설명하겠다
  • Closure Expression Syntax
    • Closure Expression Syntax는 다음과 같다
    • { ( 파라메터 ) -> 리턴타입 in
    •     내용
    • }
    • Closure Expression에서는 Parameter로 상수, 변수, inout을 사용 할 수 있다. 그러나, default 값은 사용 할 수 없으며 Variadic 타입의 경우 이름을 붙여 Parameter의 제일 마지막 부분에만 사용하는 경우만 사용이 가능하다
    • 앞서 sorted 함수에서 사용했던 backwards 함수를 Closure Expression으로 표현하면 다음과 같다.
      • var reversed = sorted(names, {
      •   (s1: String, s2: String) -> Bool in
      •   return s1 > s2
      • }
    • 이 inline closure의 파라메터와 리턴타입 선언부는 backwards 함수의 것과 동일하지만 함수와 달리 괄호 문자로 ('{') 둘러 싸여 있다는 차이가 있다.
    • inline closure는 in 이라는 키워드를 기준으로 in 이전에는 파라메터 및 리턴타입을, 이후에는 본문을 구분된다
    • 본문 내용이 그리 길지 않은 경우 다음과 같이 한 줄로 줄여서 사용 할 수도 있다
      • var reversed = sorted(names, {(s1: String, s2:String) -> Bool in return s1 > s2 })
  • Inferring Type From Context
    • sorted 함수의 경우 Closure로 넘기는 parameter의 타입으로 부터 closure의 타입을 짐작할 수 있다.
    • 앞의 예제의 경우 String Array 를 전달하게되므로 Closure 타입은 (String, String) -> Bool 이며 이를 closure expression에서는 궂이 지정할 필요는 없다
      • var reversed = sorted(names, {(s1, s2) in return s1 > s2})
  • Implicit Returns from Single-Expression Closures
    • Single-Expression Closures는 return 키워드를 생략해도 그 실행 결과가 return을 의미한다고 본다
      • var reversed = sorted(names, {(s1, s2) in s1 > s2})
    • 위의 경우는 하나의 expression ( single-expression )은 s1 > s2 이며 그 결과가 Bool 이므로 명확하게 return 값으로 처리하게 된다
  • Shorthand Argument Names
    • Swift는 inline closure에 대해 별도의 명시가 없는 경우 그 순서에 따라 $0, $1 와 같이 자동으로 shorthand argument 이름을 제공한다. 따라서, 별도의 argument를 지정하지 않는다 해도 이를 이용해서 closure를 구성 할 수 있다.
      • var reversed = sorted(names, { $0 > $1 })
      • 여기서 $0은 closure의 첫 번째 String 타입 parameter, $1는 두 번째 String 타입 parameter를 의미한다
  • Operator Functions
    • Swift에서는 앞서 예제를 가장 짧게 줄일 수 있는 방법을 제공하는데 바로 Operator Function 이다.
    • Swift는 두 개의 String 타입 Parameter와 Bool 타입의 리턴타입을 가지는 함수로 greater-than operator ( > )에 대한 구현을 정의 해 놓고 있다
    • 이는 위의 sorted 함수의 예제에 사용된 closure 타입과 정확하게 일치하므로 그냥 단순하게 greater-than operator를 closure 자리에 대치 할 수도 있다
      • var reversed = sorted(names, > )
    • 자세한 내용은 별도의 Operator Functions 항목에 자세히 설명되어 있음

Trailing Closures Expressions

closure expression을 함수의 마지막 argument로 전달하고 그 expression이 길어질 때 trailing closure라는 방식으로 작성하면 유용할 수 있다.
Training closure는 이를 지원하는 함수의 괄호 ('()') 바깥쪽 (그리고 바로 직후)에 쓰는 closure expression이다.
  • 다음과 같이 closure를 입력 받는 함수를 정의한다면
    • func test(closure:()->()) {
    •   // 본문
    • }
  • trailing closure를 사용하지 않는 호출하는 경우는 다음과 같고
    • test({
    •   // closure 본문
    • })
  • trailing closure를 사용하면 다음과 같이 호출 함수의 괄호 바깥에 놓을 수 있다
    • test() {
    •   // closure 본문
    • }
  • sorted의 예제 중 shorthanded argument를 적용해 보면 다음과 같이 줄여서 사용이 가능하다
    • var reversed = sorted(name) { $0 > $1 }

trailing closure는 single-line으로 표현하기 어려운 긴 closure를 표현할 때 가장 유용하다. Array의 map과 같은 method는 argument로 하나의 closure를 입력받는데, 해당 closure에 Array Item을 하나씩 넘겨주고, closure에서 mapping 된 새로운 정보를 리턴받는다. 이 때 기존 Array와 동일한 순서를 갖지만 새롭게 mapping된 값을 갖는 새로운 Array가 생성된다. 

  • let numstr = [1, 2, 3].map {
  •   (var num) -> String in  String(num)
  • }


    'Technical Stubs > Apple Swift' 카테고리의 다른 글

    함수 호출 문법에서 missing arguments labels가 나올 때  (0) 2014.09.18
    Swift - Closures  (0) 2014.08.12
    Swift - Function  (0) 2014.08.11
    Swift - Control Flow  (0) 2014.08.11
    Swift - Data Type #Collections  (0) 2014.08.08
    Swift - String  (0) 2014.08.08
    Trackback 0 Comment 0