본문 바로가기
Swift/기본

클로저

by 밤새는탐험가 2024. 3. 20.

클로저란?

클로저는 코드의 블럭이다. 

일급 시민으로 전달인자, 변수, 상수 등으로 저장, 전달이 가능하다. 

 

⭐️ 일급시민(frist citizen)

다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킨다.

보통 함수에 인자로 넘기기, 수정하기, 변수에 대입하기와 같은 연산을 지원한다.

 

함수클로저의 일종으로, 이름이 있는 클로저라고 생각하면 된다.

 

 

기본 클로저 문법

{ (매개변수 목록) -> 반환타입 in 
    실행 코드
}

 

 

클로저의 사용

아래에서 보면 (String) → String 을 통해 String 타입의 매개변수를 받아

String을 반환하는 함수 타입이라는 걸 알려준다.

(클로저는 이름 없는 함수이다.)

 

{ ... } 이 부분이 바로 클로저이다.

// sayHello라는 상수에 클로저를 할당 
let sayHello: (String) -> String = { (name: String) -> String in 
    return "\(name) 안녕"}

let jerry: String = sayHello("제리")

print(jerry)
// 제리 안녕 출력

 

 

함수의 전달인자로서의 클로저 

클로저는 주로 함수의 전달인자로 많이 사용된다. 

함수 내부에서 원하는 코드 블럭을 실행할 수 있다. 

 

let sayHello: (String) -> String = { (name: String) in 
    return "\(name) 안녕"}

func greetingInfo(name: String, method: (String) -> String) -> String {
    return "함수의 전달인자로 받은 클로저가 실행한 결과: " + method(name)
}

jerry = greetingInfo(name: "제리", method: sayHello)
print(jerry)

// 함수의 전달인자로 받은 클로저가 실행한 결과: 제리 안녕

 

 

다양한 클로저 표현

클로저는 다양한 모습으로 표현할 수 있다.

 

함수의 매개변수 마지막으로 전달되는 클로저후행 클로저 (trailing closure)로 

함수 밖에 구현할 수 있다. 

 

컴파일러가 클로저의 타입을 유추할 수 있는 경우 매개변수, 반환 타입은 생략할 수 있다. 

 

반환 값이 있는 경우, 암시적으로 클로저의 맨 마지막 줄은 "return" 키워드를 생략하더라도 

반환 값으로 취급합니다. 

 

전달인자의 이름이 굳이 필요없고, 컴파일러가 타입을 유추할 수 있는 경우 

축약된 전달인자 이름 ($0, $1, $2...)을 사용할 수 있다. 

 

 

클로저 매개변수를 갖는 함수 calculate(a:, b:, method:) 와

결과값을 저장할 변수 result를 먼저 선언한다. 

 

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

var result: Int

 

 

후행 클로저 

클로저가 함수의 마지막 전달인자라면 마지막 매개변수 이름을 생략한 후 

함수 소괄호 외부에 클로저를 구현할 수 있다. 

 

아래에서는 method: 이 부분이 생략되었다.

 

// 변경 전
result = calculate(a: 10, b: 10, method: { (left: Int, right: Int) -> Int in
    return left + right
})


// 변경 후
result = calculate(a: 10, b: 10) { (left: Int, right: Int) -> Int in
    return left + right
}

print(result) // 20

 

 

반환타입 생략 

calculate(a:b:method:) 함수의 method 매개변수는 Int 타입을 반환할 것이라는 사실을

컴파일러도 알기 때문에 굳이 클로저에서 반환타입을 명시해 주지 않아도 된다.

 

대신 in 키워드는 생략할 수 없다. 

 

// 후행클로저와 함께 사용할 수도 있습니다
result = calculate(a: 10, b: 10) { (left: Int, right: Int) in
    return left + right
}

print(result) // 20

 

 

단축 인자이름

클로저의 매개변수 이름이 굳이 불필요하다면 단축 인자이름을 활용할 수 있다.

단축 인자이름은 클로저의 매개변수의 순서대로 $0$1$2 처럼 표현한다.

 

result = calculate(a: 10, b: 10, method: {
    return $0 + $1
})

print(result) // 20


// 당연히 후행 클로저와 함께 사용할 수 있습니다
result = calculate(a: 10, b: 10) {
    return $0 + $1
}

print(result) // 20

 

 

암시적 반환 표현

클로저가 반환하는 값이 있다면 클로저의 마지막 줄의 결과값은

암시적으로 반환값으로 취급한다.  

 

"return" 키워드를 생략한다.

 

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

print(result) // 20

// 간결하게 한 줄로 표현해 줄 수도 있습니다
result = calculate(a: 10, b: 10) { $0 + $1 }

print(result) // 20

 

 

축약 전과 후 비교 

 

//축약 전
result = calculate(a: 10, b: 10, method: { (left: Int, right: Int) -> Int in
    return left + right
})

//축약 후
result = calculate(a: 10, b: 10) { $0 + $1 }

print(result) // 20

 

 

위에서 작성한 greetingInfo 함수에 후행 클로저를 적용한다면?

 

func greetingInfo(name: String, method: (String) -> String) -> String {
    return "실행한 결과: " + method(name)
}

var tom: String

tom = greetingInfo(name: "tom", method: { (first: String) -> String in
return "안녕 \(first)"})

print(tom)  // 실행한 결과: 안녕 tom

// 축약 후
tom = greetingInfo(name: "tom") { "안녕하세요 \($0)"}
print(tom)  // 실행 결과: 안녕하세요 tom

 

 

 

여러 매개변수 중에 데이터를 안 쓰고 싶은게 있을 때?

 

func sayHelloWithFullName(completion: (String, String) -> Void) {
    print("sayHelloWithFullName() 호출")
    sleep(2)
    completion("안녕", "안녕하세요")
}


// 만약에 특정 매개변수를 쓰고 싶지 않다면 "_" 사용한다.
sayHelloWithFullName { _, second in
     print("첫 번째: , 두 번째: \(second)")
}

// 첫 번째: , 두 번째: 안녕하세요

 

 

 

매개변수를 쓸지 말지를, 옵셔널을 적용하고 싶다면?

매개변수를 옵셔널로 감싸면 된다. 

completion: (() -> Void)? = nil

 

// 옵셔날
func sayHelloWithOptional(completion: (() -> Void)? = nil) {
    print("sayHelloWithOptional() 호출")
    sleep(2)
    
    // completion 클로저 실행
    completion?()
}
  
sayHelloWithOptional()

// 값을 반환하고 싶다면? 완료 후에 결과를 내놓고 싶을 때는 아래와 같이 쓴다.
sayHelloWithOptional(completion: {
    print("sayHelloWithOptional() 호출: 결과값 반환")
})



// sayHelloWithOptional() 호출
// sayHelloWithOptional() 호출
// sayHelloWithOptional() 호출: 결과값 반환

 

 

 

 

 

'Swift > 기본' 카테고리의 다른 글

함수  (0) 2024.03.22
컬렉션 타입  (0) 2024.03.21
기본 데이터 타입  (0) 2024.03.21
상수, 변수  (0) 2024.03.21
클로저 - @autoclosure  (0) 2024.03.20