학습
Swift 클로저(Closure) 기초
Swift 클로저(Closure) 기초 — 초급
클로저(Closure) 기초
1. 도입 (왜 배워야 하는가)
Swift에서 클로저는 매우 중요한 개념입니다. 클로저를 이해하면 코드의 재사용성과 가독성을 높일 수 있으며, 비동기 프로그래밍, 이벤트 처리, 데이터 조작 등 다양한 상황에서 유용하게 사용됩니다. 만약 클로저를 모른다면, 특히 비동기 작업이나 콜백 기능을 구현할 때 코드가 복잡해지고, 유지보수가 어려워질 수 있습니다. 예를 들어, API 호출 후 데이터를 처리하는 과정에서 클로저 없이 구현하면 코드가 비효율적으로 길어질 가능성이 큽니다.
2. 핵심 개념 설명
클로저는 일종의 "익명 함수"입니다. 함수와 비슷하게 재사용할 수 있으며, 변수를 캡처하고 상태를 유지할 수 있습니다. 실생활에서 클로저를 비유하자면, 요리사가 비법 소스를 미리 만들어 놓고 필요할 때마다 꺼내 쓰는 것과 같습니다. 요리사는 소스를 언제든지 사용할 수 있지만, 소스의 재료나 조리법은 외부와 분리되어 있습니다.
관련 용어 정리
| 용어 | 설명 |
|---|---|
| 클로저 | 함수처럼 동작하는 코드 블록 |
| 캡처 | 클로저가 외부 변수에 접근하는 것 |
| 타입 추론 | Swift가 변수의 타입을 자동으로 추론 |
3. 기본 코드 예제
다음은 클로저의 기본적인 사용법을 보여주는 간단한 코드입니다.
// 클로저 선언
let greeting = {
print("안녕하세요!")
}
// 클로저 호출
greeting()
실행 결과:
안녕하세요!
코드 한 줄씩 동작 설명:
let greeting = { ... }: 클로저를 정의하고,greeting이라는 변수에 할당합니다. 이 클로저는 "안녕하세요!"라는 메시지를 출력합니다.greeting(): 정의한 클로저를 호출하여 실행합니다. 결과적으로 "안녕하세요!"가 출력됩니다.- 클로저는 함수처럼 동작하는 코드 블록으로, 재사용성과 가독성을 높일 수 있습니다.
- 클로저는 외부 변수를 캡처하고, 비동기 작업에서 유용하게 사용됩니다.
- 클로저의 사용 예로는 배열 정렬 및 API 비동기 처리 등이 있습니다.
- 변수를 캡처할 때 주의해야 하며, 타입을 명시적으로 지정하는 것이 좋습니다.
- 클로저의 메모리 관리와 강한 참조 vs 약한 참조
- 클로저를 활용한 고차 함수
- 클로저의 escaping과 non-escaping 이해하기
4. 실전 활용 예제
예제 1: 배열 정렬
쇼핑몰에서 상품 목록을 가격에 따라 정렬할 때 클로저를 사용할 수 있습니다.
let prices = [30000, 15000, 25000, 45000]
let sortedPrices = prices.sorted(by: { $0 < $1 })
print(sortedPrices) // [15000, 25000, 30000, 45000]
상황 설명: 가격 배열을 오름차순으로 정렬하여 사용자에게 더 나은 쇼핑 경험을 제공합니다.
예제 2: 비동기 처리
API에서 데이터를 가져오는 경우 클로저를 사용하여 비동기적으로 데이터를 처리할 수 있습니다.
func fetchData(completion: @escaping (String) -> Void) {
DispatchQueue.global().async {
// 데이터 가져오기 (모의)
let data = "데이터 로드 완료"
completion(data)
}
}
fetchData { result in
print(result) // 데이터 로드 완료
}
상황 설명: 네트워크에서 데이터를 가져온 후, 클로저를 통해 결과를 처리합니다.
5. 흔한 실수와 주의사항
실수 1: 클로저 내에서 캡처한 변수를 수정하기
잘못된 코드:
var count = 0
let increment = {
count += 1
}
increment()
print(count) // 1
올바른 코드:
var count = 0
let increment = { [count] in
count += 1 // 컴파일 오류 발생, count는 수정할 수 없음
}
increment()
print(count) // 0
주의사항: 변수를 캡처할 때 값을 직접 수정하려면 inout을 사용하거나 다른 방법을 고려해야 함.
실수 2: 클로저의 타입을 명시하지 않기
잘못된 코드:
let operation = {
return 5 + 10
} // 타입이 불명확
let result: Int = operation() // 컴파일 오류
올바른 코드:
let operation: () -> Int = {
return 5 + 10
}
let result: Int = operation() // 올바르게 작동
주의사항: 클로저의 타입을 명시적으로 지정하여 오류를 방지할 수 있습니다.