Closure
Closure는 Unnamed function, 이름이 없는 함수에요.
함수와 마찬가지로 1급 시민이지만, 함수와 다르게 argument label 사용 하지 않아요.
Syntax!
{ (parameters) -> Return Type in
statements
}
// 함수와 동일하게 파라미터와 리턴 타입 생략 가능
{ statements } // 위와 동일한 closure
클로저는 global scope에서 단독으로 사용 불가, 상수나 변수에 저장하여 사용해야해요.
아무래도 이름이 없는 함수니까 냅다 클로저만은 사용할 수 없겠죵 ?
이렇게 저장해서 사용해야합니다. (당연히 매개변수로 넣을 수 있음)
let c = { (str : String) -> String in
return "Hello \\(str)"
}
처음 클로저를 접하시는 많은 분들이 엥 이게 클로저라고...?
라는 생각이 들법한 클로저가 상당히 많은데
이유는 클로저는 정말 극한으로 단축할 수 있기 때문입니다... 이거를 문법 최적화라고 해요!
이거는 그냥 실제로 써보면서 익숙해지는게 제일 베스트라고 생각합니다.. 'ㅅ'
Closure 문법 최적화 (Syntax Optimization)
- 파라미터 형식과 리턴 형식 생략 가능
- 파라미터 이름과 in 키워드 생략하고, 이름을 단축 인자로 대체
- 단일 리턴문 이라면 리턴 키워드 생략
- 클로저가 마지막 파라미터라면 trailing closure로 대체
- ()안에 다른 파라미터가 없다면 () 생략
products.filter({ (name: String) -> Bool in
return name.contains("Pro")
})
// 1. 파라미터형식과 리턴 형식 생략 가능 (형식!!의 생략)
products.filter({ (name) in
return name.contains("Pro")
})
// 2. 파라미터 이름과 in 키워드 생략하고 이름을 축약익자로 대체
products.filter({
return $0.contains("Pro")
})
// 3. 단일 return 이라면 return 생략
products.filter({
$0.contains("Pro")
})
// 4. closure가 마지막 파라미터라면 trailing closure로 작성
products.filter() {
$0.contains("Pro")
}
// 5. () 안에 다른 파라미터가 없다면, ()생략
products.filter {
$0.contains("Pro")
}
두 번째 예시,
proModels.sort(by: { (lhs: String, rhs: String) -> Bool in
return lhs.caseInsensitiveCompare(rhs) == .orderedAscending
}
// 결과
proModels.sort {
lhs.caseInsensitiveCompare($1) == .orderedAscending
}
Closure Capture (클로저의 값 참조)
클로저는 참조를 복사(캡쳐)하기 때문에 클로저 내부에서 값을 변경하면 원래 값도 변경돼요. (힙에 생성되기 때문에 힙)
클로저 내부에서 외부에 있는 값에 접근하면, 값에 대한 참조를 획득하기 때문에 내부에서 값 변경 시 외부의 원래값도 변경 됩니다.
* 잠시 힙에 대한 설명을 하자면
- 동적으로 할당되는 메모리 이면서, 크기가 큰 데이터를 적재하곤 함
- 참조 형식의 값이 저장되는 곳(주소는 stack에 저장)
- 클래스, 클로저가 해당함
var num = 0
let c = {
num += 1
print("num1 : \\(num)") // 1
}
c()
print("num2 : \\(num)") // 1
(그래서 참조 사이클 문제가 발생하기도 함) <~~ 이건 나중에 다른 게시물로 써볼게요.
Escaping Closure
함수의 실행 흐름과 관계없이 클로저를 실행할 수 있도록 해주는 키워드?입니다.
함수가 끝나도 함수 안에 있는 클로저는 상관없이 실행 가능하도록 해줍니다.
어디서 쓰냐면.. 네트워킹 통신할 때 씁니다. (통신은 시간이 오래걸리니까 클로저로 받아서 처리해요)
func performEscaping(closure: @escaping () -> ()) {
print("start")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
closure()
}
print("end")
}
performEscaping {
print("closure")
}
escaping 키워드를 사용함으로써 3초 뒤에 실행되는 closure()를 함수가 끝난 뒤에 실행할 수 있는 것입니다!
클로저는 여기까지.
노션에 정리한거 좀 더 살을 붙인것이라서 ..
말이 어색할 수 있으나 정리 완료~!
이상한 개념이 있다면 댓글 남겨주세요 !
'Swift > Swift 기초문법' 카테고리의 다른 글
[Swift 기초문법] Generics을 알아보자 (0) | 2023.07.10 |
---|---|
[Swift 기초문법] Property를 알아보자 (0) | 2023.06.16 |
[Swift 기초문법] Optional Chaining에 대해 알아보자 (2) | 2023.03.02 |
[Swift 기초문법] Optional Binding을 알아보자 (3) | 2023.02.26 |
[Swift 기초문법] Optional을 알아보자 (2) | 2023.02.11 |