-
[Swift] 클로저란?iOS 2022. 1. 4. 21:43
스위프트에는 '클로저(Closure)' 라는 개념이 존재한다.
클로저는 코드의 블럭이라고 볼 수 있는데, 우리가 흔히 사용하는 함수도 클로저이다.
클로저는 크게 Named Closure 와 UnNamed Closure 이렇게 2가지로 나눠진다.
우리가 주로 클로저를 말할땐 UnNamed Closure 를 지칭하고 함수는 Named Closure 에 포함된다.
클로저의 기본 구조는 아래와 같다.
{ (매개변수 리스트) -> 반환타입 in 실행할 코드 }
클로저는 1급 객체로, 변수 형태로 저장할 수 있고 함수의 파라미터로도 넘길 수 있다.
여기서 말하는 1급 객체란 함수형 프로그래밍에서 쓰이는 개념으로, 아래의 조건을 만족하는 객체를 말한다.
1. 변수나 상수에 저장 및 할당이 가능하다.
2. 함수의 파라미터로 전달이 가능하다.
3. 함수에서 리턴이 가능하다.
위 조건들에 대한 예시를 각각 보자.
1. 변수나 상수에 저장 및 할당이 가능하다.
// closureSample 상수에 할당 let closureSample = { (city: String) -> String in "I'm in \(city)" } // 할당된 클로저 실행 closureSample("서울")
2. 함수의 파라미터로 전달이 가능하다.
// 상수에 클로저 할당 let sayHello = { (name: String) -> String in "Hello \(name)" } // 상수에 클로저 할당 let sayGoodbye = { (name: String) -> String in "Goodbye \(name)" } // 함수의 파라미터로 클로저를 전달받도록 정의 func greet(name: String, sayWhat: (String) -> String) { sayWhat(name) } // 함수 파라미터로 클로저 전달 // 리턴값 : Hello 이름 greet(name: "Jaebin", sayWhat: sayHello) // 함수 파라미터로 클로저 전달 // 리턴값 : Goodbye 이름 greet(name: "Jaebin", sayWhat: sayGoodbye) // 상수 클로저를 전달하지 않고 직접 클로저를 구현해 전달 가능 greet(name: "Jaebin", sayWhat: {( displayName: String) -> String in "How are you \(displayName)?" })
3. 함수에서 리턴이 가능하다.
// 함수의 리턴값으로 클로저 반환 func saySomething(word: String) -> (String) -> String { return { (word) -> String in "I said \(word)" } } // 리턴된 클로저를 상수에 할당 let say = saySomething("Hello") // 클로저 호출 // 리턴값 : I said Hello say()
지금까지만 봤을때는 클로저가 너무 복잡해보이고 왜 사용하는지도 모를 것이라 생각한다.
하지만 이 길고 복잡한 클로저는 축약이 가능하다.
반환 타입 생략
3번 예시를 보자.
위 saySomething 함수에서 리턴되는 클로저에서 우리는 리턴값이 당연히 String 형식이라는 것을 알 수 있다.
이는 컴파일러도 판단할 수 있기 때문에 반환 타입을 명시하지 않아도 된다. 따라서 아래와 같이 반환 타입을 생략하고 표현이 가능하다.
// 축약 전 func saySomething(word: String) -> (String) -> String { return { (word) -> String in "I said \(word)" } } // 축약 후 func saySomething(word: String) -> (String) -> String { return { (word) in "I said \(word)" } }
트레일링 클로저
2번 예시를 보자.
마지막 호출 방법인 직접 클로저를 작성하는 방식에서 축약이 가능하다.
클로저가 함수의 마지막 매개변수일 시 이름을 생략하고 클로저를 구현할 수 있다.
// 축약 전 greet(name: "Jaebin", sayWhat: {( displayName: String) -> String in "How are you \(displayName)?" }) // 축약 후 greet(name: "Jaebin") {( displayName: String) -> String in "How are you \(displayName)?" }
인자명 단축
3번 예시를 보자.
예시에서는 클로저로 넘기는 인자명이 word 로 짧지만 긴 인자명일 수 있다.
이 때, 인자명을 모두 적지 않고 아래와 같이 축약이 가능하다.
// 축약 전 func saySomething(word: String) -> (String) -> String { return { (word) -> String in "I said \(word)" } } // 축약 후 func saySomething(word: String) -> (String) -> String { return { (word) -> String in "I said \($0)" } }
인자 순서대로 $0, $1, $2.. 와 같이 번호가 자동으로 매겨져 이를 이용해 인자명을 단축할 수 있다.
댓글