본문 바로가기

스폰지밥으로 공부하는 swift/swift 문법

클로저 왜 씀?

728x90

클로저 그게 뭔데요?

swift.org에 따르면 클로저는 이름없는 함수(코드 블록)을 말합니다. C 및 Objective-C의 블록과 JAVA의 람다와 유사하다고 하네요!

클로저는 상수나 변수의 참조를 캡쳐(capture)해 저장할 수 있습니다.

클로저를 사용하는 이유

한마디로 말씀드리자면 코드를 굉장히 간결하게 작성할 수 있어요!

집게리아에서 주문(order)를 받아 처리한 결과를 문자열로 반환하는 동작인데요,

 

let orderProcessing: (String) -> String = { order in
    return "주문하신 \(order)를 만들었습니다."
}
print(orderProcessing("크랩버거"))

동일한 기능을 수행하는 함수:

func orderProcessing(order: String) -> String {
    return "주문하신 \(order)를 만들었습니다."
}
print(orderProcessing(order: "크랩버거"))

클로저를 사용하면 함수를 정의하고 호출하는 것에 비해 코드를 더 간결하게 작성할 수 있어요. 이는 특히 간단한 기능을 수행하는 코드 블록에 대해 유용하고 코드의 가독성을 향상시킬 수 있답니다.

forEach 함수를 사용하여 각 재료를 게살버거에 추가하는 코드도 하나 더 보실게요!

let 게살버거재료 = ["빵", "게살패티", "치즈", "양상추", "토마토"]

func 재료추가(재료: String) {
    print("\(재료)를 게살버거에 추가합니다.")
}

게살버거재료.forEach(재료추가)

보시다시피 함수 없이 훨씬 간단하게 구현이 가능하죠?

let 게살버거재료 = ["빵", "게살패티", "치즈", "양상추", "토마토"]

게살버거재료.forEach { 재료 in
    print("\(재료)를 게살버거에 추가합니다.")
}

foreach 메서드는 제가 addSubviews할때도 굉장히 애용중입니다 ㅎㅎ

클로저의 장단점

  • 장점
    • 여러 작업을 동시에 처리하거나, 코드의 실행을 연기하거나, 코드를 '캡슐화'하여 한 덩어리로 관리하는 데에 매우 유용합니다.
    • 클로저는 간결하게 코드를 작성할 수 있도록 도와줍니다.
  • 단점
    • 클로저의 캡처 특성 때문에 순환 참조의 위험이 있습니다. 따라서 메모리 관리에 주의해야 합니다.
    • 클로저의 사용이 복잡해질수록 코드의 가독성이 떨어질 수 있습니다.

언제 많이 사용하나요?

클로저는 네트워크 요청이나 애니메이션 완료 후 특정 작업을 수행하는 등 비동기 작업에서 많이 사용됩니다.

클로저의 활용

클로저는 변수나 상수 등에 할당할 수 있으며, 함수의 매개변수로 전달하거나 결과값으로 반환할 수 있습니다.

집게사장이 주문을 받아 처리하는 것은 함수로, 그 과정에서 발생하는 요리 조리 과정을 클로저로 구현해볼게요.

func processOrder(order: String, completion: (String) -> Void) {
    completion("주문하신 \(order)를 만들었습니다.")
}

let cooking: (String) -> Void = { order in
    print("주문하신 \(order)를 만들고 있습니다.")
}

processOrder(order: "크랩버거", completion: cooking)

이 예시에서 cooking이 바로 클로저입니다. 이 클로저는 processOrder 함수의 매개변수로 전달되어 주문이 처리되는 과정을 출력합니다.

클로저의 캡처리스트

클로저는 주변의 상수나 변수를 '캡처'할 수 있는데요, 캡처를 하면 클로저 내부에서 주변의 상수나 변수를 참조할 수 있습니다. 이를 '클로저의 캡처리스트'라고 해요.

 

클로저의 캡처리스트는 클로저가 생성될 때 주변 환경(context)의 변수나 상수를 '기억'하는 역할을 합니다.

 

우리가 일을 미루다가 나중에 그 일을 다시 진행할 때, 그 때의 상황을 기억하고 그에 맞춰 일을 하죠?

 

이처럼 클로저도 캡처리스트를 통해 생성 시점의 주변 환경의 상태를 '기억'하고 이를 이용해 나중에 독립적으로 동작해요.

var crabBurgerCount = 0

let addCrabBurger: () -> Void = { [crabBurgerCount] in
    print("크랩버거 \(crabBurgerCount + 1)개를 추가했습니다.")
}

addCrabBurger()

이 예시에서 addCrabBurger 클로저는 crabBurgerCount 변수를 캡처하여 개수를 증가시킵니다.

클로저의 생략 문법

Swift의 클로저는 문법을 간소화할 수 있는 여러 가지 방법을 제공합니다. 예를 들어, 파라미터와 반환 타입을 생략하거나, 단축 인자 이름을 사용할 수 있습니다.

let orderProcessing: (String) -> String = { order in
    return "주문하신 \(order)를 만들었습니다."
}

// 간소화 버전
let orderProcessing = { (order: String) in "주문하신 \(order)를 만들었습니다." }

위 코드처럼 클로저의 타입 추론 기능을 활용하면 파라미터와 반환 타입을 생략할 수 있어요. 그리고 단축 인자 이름을 사용하면 인자에 대한 별도의 이름을 지정하지 않고 클로저를 구현할 수 있습니다.


한 줄 요약

클로저는 코드의 재사용, 간결성, 비동기 처리 등을 위해 사용되는 독립적인 코드 블럭이고, 메모리 관리와 가독성에 주의해야 합니다.