Swift + iOS/Swift

[Swift] Closure [01]

군옥수수수 2017. 9. 22. 00:40

Closure - Basic


클로저는 func 키워드와 함수의 이름이 없는 함수입니다. 흔히들 익명함수라고 불리기도 합니다. 이들은 이름이 없기 때문에 그들 스스로 호출을 할 수 없습니다.


  • 기본 클로저 문법
{ (매개변수 목록) -> 반환타입 in
    실행 코드
}

함수 vs 클로저

Function

  • 이름이 있다.
  • func 키워드가 존재한다.
  • in 키워드가 존재하지 않는다.
Closure

  • 이름이 없다.
  • func 키워드가 존재하지 않는다.
  • in 키워드가 존재한다.
func giveFunc(){ ... } // function
var giveNoFunc = {() ->in ... } // closure

//call

giveFunc()
giveNoFunc()

Function to Closure

example function code

func sayHello(name : String) -> String {
    return "Hello \(name)"
}

문자열을 인자로 받고 문자열을 반환하는 함수입니다. 이 함수를 클로저로 바꿔보도록 하겠습니다.

  1. 중괄호를 제거한다.

    func sayHello(name : String) -> String
        return "Hello \(name)"
    
  2. in키워드를 함수의 본체와 반환타입 사이에 추가합니다.

    func sayHello(name : String) -> String in
        return "Hello \(name)"
    
  3. func키워드와 함수의 이름을 제거합니다.

    (name : String) -> String in
        return "Hello \(name)"
    
  4. 전체를 중괄호로 감쌉니다.

    {(name : String) -> String in
        return "Hello \(name)"
    }
    

끝입니다! 이제 클로저를 변수에 할당 후 사용이 가능합니다.

var sayHello = { (name : String) -> String in
    return "Hello \(name)"
} 

sayHello("Dongkeon")
// Output "Hello Dongkeon"

그렇다면 생각하실겁니다! 언제 클로져를 사용하지?
클로저는 상당히 많은 곳에서 사용되며 ios개발을 하면서 절대적으로 알아야할 문법 중 하나입니다. 사용되는 예로는 completion blocks, callbacks 고차함수 등등 많은 곳에 사용됩니다.

클로저의 문법은 가독성이 좋다는 장점이 있습니다. 이러한 장점으로 인해 여러 종류의 축약형이 존재합니다. 이러한 축약형을 하나씩 살펴보도록 하겠습니다.


  1. return 값으로 반환되는 타입을 추측가능

    var sayHello = { (name : String) in 
        return "Hello \(name)"
    }
        
    /*
    클로저에서는 return 키워드 또한 생략해줄 수 있습니다. 마지막에 있는 값을 반환 값으로 인식합니다.
    */
        
    var sayHello = { (name : String) in 
        "Hello \(name)"
    }   
    
  2. 변수의 타입을 명시해주었다면 매개변수의 타입도 생략 가능

    var sayHello : (String)->String = { "Hello \($0)" }
        
    /*
    $ 사인을 통해 매개변수를 0 부터 순서대로 접근 할 수 있습니다.
    */
    

클로저의 기본 문법과 이의 축약 형태를 비교해보시면 확실히 축약형이 코드를 작성하기 편하고 이러한 문법을 알고있다면 가독성 또한 좋다는 것을 아실 수 있습니다.

비교

// 기본 문법
var sayHello = { (name : String) -> String in
    return "Hello \(name)"
} 
// 축약형
var sayHelloTwo : (String)->String = { "Hello \($0)" }

전달인자로서의 클로저

출처 : Yagom님의 블로그

클로저는 주로 함수의 전달인저로 많이 사용됩니다. 함수 내부에서 원하는 코드블럭을 실행 할 수 있습니다.

let add: (Int, Int)-> Int = add = { $0 + $1 }
let substract: (Int, Int)-> Int = add = { $0 - $1 }
let divide: (Int, Int)-> Int = add = { $0 / $1 }
let multiply: (Int, Int)-> Int = add = { $0 * $1 }

func calculate(a:Int, b:Int method:(Int,Int)->Int)->Int{
    return method(a,b)
}

print(calculate(a:4, b:2, method:add)) // 6
print(calculate(a:4, b:2, method:substract)) // 2
print(calculate(a:4, b:2, method:divide)) // 2
print(calculate(a:4, b:2, method:multiply)) // 8 

후행 클로저

출처 : Yagom님의 블로그

클로저가 함수의 마지막 전달인자이거나 전달인자가 클로저 하나뿐이라면 전달인자로 넘기지 않고 함수를 호출 후 중괄호를 통해 클로저를 구현해줌으로써 인자 전달이 가능합니다.

result = calculate(a:3, b:2) { (left:Int, right:Int) -> Int in
    return left + right
}
// 이 또한 축약형으로 작성 가능합니다.

result = calculate(a:3, b:2) { $0 + $1 } 

// 이 때  $0 + $1처럼 구현이 아닌 변수 add 를 넘기는 것은 불가능합니다.

이 자료를 보아도 해당 문법을 정확히 어디에 쓰이는지 감이 오지 않을 수도 있습니다. 하지만 당장 어디에 사용되는지 몰라도 다른 사람들의 코드를 볼 때
“아! 이것이 인자로 넘어가는구나!”
“아! 이것이 클로저구나!”
라며 코드를 이해하는데 도움이 됩니다. 용도는 추후의 자료를 통해 살펴보도록 하겠습니다.