클로저의 문법 최적화
클로저는 왜 사용하는가?
- 클로저는 함수처럼 동작하지만, 정의와 전달이 유연하다는 장점이 있다
- 주로 함수의 파라미터로 전달하거나 간단한 동작을 즉시 정의할 때 사용한다
- 함수의 흐름 중 특정 시점에 실행할 동작을 외부에서 주입할 수 있어 활용도가 높다
클로저에 이름이 필요 없는 이유
- 클로저는 대부분 일회성 작업이나 간단한 동작을 정의할 때 사용된다
- 이름을 붙이지 않아도 되므로 코드가 간결하고 직관적으로 작성될 수 있다
- 특히 클로저를 파라미터로 직접 전달할 때는 이름 없는 형태가 더 자연스럽다
- 복잡한 로직이 없는 짧은 작업에는 이름 없이 사용하는 것이 일반적이다
클로저의 문법 최적화
- 클로저는 더 간결하게 사용하기 위해 다음과 같은 문법 최적화를 제공한다.
- 클로저 문법 최적화 방식:
- 1) 문맥에서 파라미터와 리턴 타입을 추론(Type Inference)
- 2) 단일 표현식(한 줄)인 경우,
return 키워드를 생략(Implicit Return)
- 3) 매개변수 이름을 축약(Shorthand Arguments) ->
$0, $1, ...
- 4) 트레일링 클로저(Trailing Closure) 문법 사용
예제 1: 트레일링 클로저 사용
func performAction(action: () -> Void) {
print("동작 시작")
action()
print("동작 종료")
}
performAction(action: {
print("중간 작업 실행")
})
동작 시작
중간 작업 실행
동작 종료
performAction {
print("중간 작업 실행")
}
동작 시작
중간 작업 실행
동작 종료
performAction 함수는 () -> Void 형태의 클로저를 파라미터로 받아 동작의 중간에 실행한다
- 일반적인 클로저 전달 방식은
action: { ... } 형태로 사용
- 클로저가 마지막 파라미터라면 트레일링 클로저 문법을 사용할 수 있으며, 이때는 함수 호출 괄호를 생략 가능
- 트레일링 클로저는 코드의 가독성과 간결함을 높여준다
예제 2: 파라미터 및 생략 최적화
func transform(text: String, using closure: (String) -> Int) {
let length = closure(text)
print("문자 수: \(length)")
}
transform(text: "Hello", using: { (input: String) -> Int in
return input.count
})
transform(text: "Hello", using: { (input) in
return input.count
})
transform(text: "Hello", using: { input in
input.count
})
transform(text: "Hello", using: {
$0.count
})
transform(text: "Hello") {
$0.count
}
- 이 예제는
String을 입력 받아 길이(Int)를 반환하는 다양한 클로저 표현 방식을 보여줌
- Step 2에서는 전체 타입을 명시하고
return을 사용
- Step 3~4에서는 타입 추론과
return 생략
- Step 5는
$0을 사용한 축약 문법
- Step 6은 트레일링 클로저 문법까지 적용한 최종 간결 형태
- 이렇게 점진적으로 최적화해가며 더 읽기 쉬운 코드로 발전시킬 수 있다
클로저의 실제 활용 예시
- 클로저는 UIKit과 같은 프레임워크에서 매우 자주 사용되는 기능이다
- 특히 비동기 작업, 타이머, 애니메이션, 화면 전환 처리 등 다양한 상황에서 클로저가 활용된다
URLSession - 네트워크 요청 처리
import Foundation
let url = URL(string: "https://example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("에러 발생: \(error)")
} else if let data = data {
print("데이터 수신 완료: \(data.count)바이트")
}
}
task.resume()
dataTask는 네트워크 작업을 비동기로 수행하고 응답이 오면 클로저를 실행하는 구조이다
- 클로저 내부에서는
data, response, error를 통해 결과를 확인하고 처리할 수 있다
Timer - 일정 시간 후 작업 실행
import Foundation
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { timer in
print("1초 뒤에 실행되었습니다")
}
Timer는 지정된 시간이 지난 후 클로저를 실행하는 기능을 제공한다
- 클로저는 특정 시점에 실행될 작업을 정의하는 데 매우 적합한 도구이다
UIViewController.dismiss - 화면 닫기 후 작업 실행
import UIKit
class MyViewController: UIViewController {
func closeView() {
dismiss(animated: true) {
print("화면을 닫는 것이 완료되었습니다")
}
}
}
dismiss(animated:completion:)은 화면이 닫힌 후 실행할 동작을 클로저로 받는 메서드이다
- 클로저를 통해 화면 전환 후 후속 작업을 유연하게 정의할 수 있다
멀티 트레일링 클로저(Swift 5.3 이상)
- 여러 개의 클로저를 인자로 받는 함수에서는 Swift 5.3부터 각각의 클로저를 트레일링 클로저 형태로 표현할 수 있다
멀티 클로저 함수 정의 및 사용
func runMultipleTasks(first: () -> Void, second: () -> Void, third: () -> Void) {
first()
second()
third()
}
runMultipleTasks(first: {
print("첫 번째 작업")
}, second: {
print("두 번째 작업")
}) {
print("세 번째 작업")
}
첫 번째 작업
두 번째 작업
세 번째 작업
runMultipleTasks {
print("작업 1")
} second: {
print("작업 2")
} third: {
print("작업 3")
}
작업 1
작업 2
작업 3
UIView.animate - 실사용 예시
import UIKit
UIView.animate(withDuration: 0.3) {
print("애니메이션 실행 중")
} completion: { finished in
print("애니메이션 완료: \(finished)")
}
애니메이션 실행 중
애니메이션 완료: true
UIView.animate는 애니메이션 실행과 완료 시 각각의 동작을 클로저로 정의하는 함수이다
- Swift 5.3의 트레일링 클로저 문법을 활용하면 코드의 가독성이 향상된다
요약
- 클로저는
UIKit, Foundation 등에서 콜백 처리를 위해 자주 사용되는 기능이다
- 클로저는 비동기 작업 처리, 이벤트 이후 동작, 애니메이션, 타이머 등에 적합한 방식이다
- Swift 5.3 이후에는 여러 개의 클로저도 트레일링 클로저 문법으로 간결하게 표현할 수 있다
- 실무에서는 클로저를 통해 실행 흐름을 유연하게 제어할 수 있다