클로저
- 익명함수 또는 내장함수라고 불립니다.
- 코드에서 일급 객체로 사용할 수 있는 기능블록입니다.
- 클로저는 코드에서 다른 함수로 전달되거나, 변수에 저장되거나, 나중에 호출될 수 있습니다.
- 함수와 매우 유사하지만 정확히 함수는 아닙니다.
클로저는 크게 3가지 형태로 사용됩니다.
1. 전역함수
_ 이름이 있으며, 특정 컨텍스트에 속하지 않습니다.
2. 중첩함수
_ 이름이 있으며, 다른 함수 내부에 정의됩니다.
3. 클로저 표현식
_ 이름이 없으며, 간결한 문법으로 작성할 수 있습니다. 일반적으로 이 형태를 클로저라고 부릅니다.
클로저의 기본문법
클로저는 입력 파라미터, 반환타입, 그리고 실행할 코드 블록으로 구성됩니다.
{ (parameters) -> returnType in
// 실행할 코드
}
예시
let greeting = { (name : String) -> String in
return "Hello, \(name)"
}
let message = greeting ("Alice")
print(message) // Hello, Alice
클로저는 다음과 같이 간단하게 작성할 수 있습니다.
1. 파라미터와 반환타입이 이미 정의되어있으면, 이를 생략할 수 있습니다.
let greeting = { name in
return "Hello \(name)"
}
2. 클로저가 단일 표현식으로 이루어져 있으면, return 키워드를 생략할 수 있습니다.
let greeting = { name in
"Hello, \(name")
// return 생략
}
3. 클로저에서 파라미터 이름을 $0, $1등으로 축약하여 사용할 수 있습니다.
let greeting = {"Hello, \($0)"}
4. 후행 클로저 _ 클로저가 함수의 마지막 인자로 전달될 때, 클로저를 함수 호출 괄호 밖에 작성할 수 있습니다.
// 원형
let sortedNames = names.sorted(by: { (first: String, second: String) -> Bool in
return first < second
})
let names = ["james", "rodrigues", "john", "methew"]
// 1번째 형태 : 단일 표현식일 경우에 return을 생략할 수 있다.
let sortedNamesClosure1 = names.sorted( by : {
(first: String, second : String) -> Bool in
first < second
})
// 2번째 형태 : 반환형을 생략할 수 있다.
let sortedNamesClosure2 = names.sorted( by: {
(first : String, second : String) in
first < second
})
// 3번째 형태 : 마지막 인자로 전달되는 클로저는 후행 클로저로 작성할 수 있다.
let sortedNamesClosure3 = names.sorted{
(first : String, second : String) in
first < second
}
함수와 클로저의 차이점
ㄴ 1. 함수는 이름을 가질 수 있지만, 클로저는 일반적으로 이름이 없는 익명함수입니다.
let greeting = { (name: String) -> String in
return "Hello, \(name)!"
}
ㄴ 2. 클로저는 정의된 범위 안의 변수나 상수를 캡쳐하여 저장할 수 있으나, 함수는 일반적으로 불가능합니다.
아래 예시에서 클로저는 total과 incrementAmount를 캡쳐하여 함수가 호출된 후에도 사용할 수 있습니다.
func makeIncrementer(incrementAmount: Int) -> () -> Int {
var total = 0
let incrementer: () -> Int = {
total += incrementAmount
return total
}
return incrementer
}
let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo()) // 2
print(incrementByTwo()) // 4
ㄴ 3. 클로저는 함수에 비해서 매우 간결한 문법을 사용할 수 있습니다. 특히 swift 에서는 클로저의 파라미터 및 반환 타입을 추론할 수 있으며, 파라미터 이름을 생략할 수 있습니다.
let doubled = numbers.map { $0 * 2 }
ㄴ 4. 후행 클로저 _ 클로저는 함수의 마지막 인자로 전달될 때, 후행 클로저 문법을 사용할 수 있습니다. 함수는 이와 같은 특별한 문법이 없습니다.
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
클로저의 주요 특징
1. 캡쳐 _ 클로저는 정의된 범위 내의 상수와 변수를 캡쳐하고 저장할 수 있습니다. 이로 인해서 클로저가 생성된 범위 밖에서도 해당 변수와 상수에 접근할 수 있습니다.
func makeIncrementer(incrementAmount: Int) -> () -> Int {
var total = 0
let incrementer: () -> Int = {
total += incrementAmount
return total
}
return incrementer
}
let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo()) // 2
print(incrementByTwo()) // 4
여기서 클로저는 total과 incrementAmount 변수를 캡쳐하여 클로저 내부에서 사용할 수 있습니다.
2. 탈출 클로저 escaping closures _ 함수가 반환된 후에도 실행될 수 있는 클로저를 말합니다. 이러한 클로저는 보통 비동기 작업에서 사용됩니다. 탈출 클로저는 함수의 파라미터로 전달될 때 @escaping 키워드가 필요합니다.
그러니까 performAsyncOperation 함수 실행이 끝난 후에 콜백으로 completion() 이 실행된다. 함수 동작 마지막에 수행되는게 아니라 끝난 다음에 콜백으로 호출되는 것이다.
func performAsyncOperation(completion : @escaping () -> Void){
DispatchQueue.global().async{
// 비동기 작업 수행
completion() // 작업이 끝난 후 클로저 호출
}
}
3. 비탈출 클로저 _ 기본적으로 함수가 종료되기 전에 실행되어야 하는 클로저로 @escaping 키워드가 필요하지 않습니다.
'Ios' 카테고리의 다른 글
Ad Hoc으로 IOS 어플리케이션 내부 배포하기 (3) | 2024.09.09 |
---|---|
RESTful API 사용하기 (0) | 2024.08.21 |
self에 대해서 알아보자 (0) | 2024.08.16 |
struct 그리고 class (0) | 2024.08.16 |
as에 대해서 알아보자 (0) | 2024.08.16 |