ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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.. 와 같이 번호가 자동으로 매겨져 이를 이용해 인자명을 단축할 수 있다.

    댓글

Designed by Tistory.