클로저는 변수처럼 저장할 수 있는 코드 덩어리(함수)다. 함수와 비슷한 구조지만 이름이 없어도 사용 가능하고, 함수보다 더 유연하게 동작한다.
// 기본 구조
{ (매개변수) -> 반환타입 in
실행할 코드
}
// 예
let greeting = { (name: String) -> String in
return "Hello, \(name)"
}
print(greeting("Luna")) // 출력: Hello, Luna
func operateOnNumbers(_ a: Int, _ b: Int, using operation: (Int, Int) -> Int) {
let result = operation(a, b)
print("결과: \(result)")
}
// 클로저를 넘김
operateOnNumbers(3, 5, using: { (x, y) in
return x + y
})
// 1. 전체 코드
{ (x: Int, y: Int) -> Int in
return x + y
}
// 2. 타입 추론 생략
{ x, y in
x + y
}
// 3. 단축 인자 이름 사용
{ $0 + $1 }
클로저가 함수의 마지막 인자일 때는 괄호 밖으로 꺼낼 수 있다.
UIView.animate(withDuration: 0.5, animations: {
view.alpha = 0
})
// 트레일링 클로저 방식
UIView.animate(withDuration: 0.5) {
view.alpha = 0
}
변수 캡처: 자신이 정의된 스코프의 외부 변수를 기억해서 나중에도 사용 가능
func makeCounter() -> () -> Int {
var count = 0 // count는 함수 안에서 선언됐지만, 클로저가 기억하고 있음.
return {
count += 1
return count
}
}
let counter = makeCounter()
print(counter()) // 1
print(counter()) // 2
간결하고 유연한 코드 작성
map, filter, reduce)코드 응집력 향상
비동기 작업에서 콜백 처리에 최적
외부 변수 캡처 가능
재사용성과 추상화
캡처에 의한 강한 참조(메모리 누수 가능성)
self를 강하게 참조하면 retain cycle이 발생할 수 있다[weak self], [unowned self] 사용하여 해결디버깅 어려움
복잡한 중첩 구조
| 상황 | 사용 방식 |
|---|---|
| 콜백 처리 | 비동기 작업 결과 처리 |
| UI 애니메이션 | UIView.animate |
| 컬렉션 처리 | map, filter, reduce |
| 이벤트 핸들링 | 버튼 클릭 시 액션 |
| 타이머/딜레이 | DispatchQueue.main.asyncAfter |
// 1. 애니메이션
UIView.animate(withDuration: 1.0) {
someView.alpha = 0
}
// 2. 버튼 이벤트 핸들러
button.addAction(UIAction { _ in
print("버튼 클릭됨!")
}, for: .touchUpInside)
// 3. 배열 고차 함수
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
print(doubled) // [2, 4, 6, 8, 10]