클로저
간단하게 클로저를 먼저 정리해보자.
- 함수는 이름이 있는 클로저
- 클로저는 1급 객체이다.
- 클로즈는 참조타입이므로 기본적으로 힙에 할당된다.
- Closure란 내부 함수와 내부 함수에 영향을 미치는 주변 환경을 모두 포함한 객체이다.
클로저 캡처
- 클로저 캡처란 매개변수나 지역변수가 아닌 외부 context를 사용하기 위해 주변 외부의 context를 참조하는 것
- 클로저는 값을 캡처할 때, Value / Reference 타입에 관계 없이 모두 Reference 캡처를 사용한다. 즉 , 참조를 한다는 뜻
캡처 리스트
- 값 타입은 값을 복사해서 캡처 - 외부 요인에 의한 값 변경을 방지!
- 참조 타입은 캡처리스트 내에서 weak, unowned 참조 선언 (강한 참조 해결)
클로저와 self
@escaping 키워드
클로저와 self의 관계를 가기전에 @escaping 키워드에 대해 잠시 알아보자.
var 함수저장변수: (() -> Void)?
/// @escaping 키워드 파라미터가 지금 실행되고 있는 스코프를 벗어나서도 쓰인다.
func 탈출클로저(함수파라미터: @escaping () -> Void) {
함수저장변수 = 함수파라미터 // 외부 변수에 클로저(참조타입) 저장되면 힙에 저장되어 오래쓰임
// 캡처현상이 발생 가능 O
}
/// 인풋(함수파라미터)가 힙(Heap)에 저장이 안됨(오랫동안 쓰이지 않음) ===> 캡처현상이 발생 X
func 기본클로저(함수파라미터: () -> Void) {
함수파라미터() // 외부 스코프로 나가지 않음, 힙에 저장 x , 캡쳐핸상 발생 x
}
클래스에서 클로저
self 캡처 여부 | 이유 | |
탈출 클로저 | O | 변수를 소유하고 있는 self 자체를 캡처하기 때문에 |
기본 클로저 | X | 암시적으로 self를 참조 |
class 클래스 {
var x = 10
func doSomething() {
탈출클로저 { in
self.x = 100 /// 명시적 self 참조, 나중에 호출시 실행
}
기본클로저 { /// 즉시 실행
x = 200 /// 암시적 self참조
}
}
}
- 클래스에서 탈출 클로저는 항상 self를 붙혀야한다. 혹은 캡처 리스트 작성
- 기본 클로저는 self를 붙히지 않아도 됨, 암시적으로 self를 참조
값타입에서 클로저
self 캡처 여부 | 이유 | |
탈출 클로저 | 오류 | self에 대한 변경이 불가 값타입이니 값 복사가 일어나 원본을 바꿀 수 없으므로 |
기본 클로저 | X | 암시적으로 self를 참조 |
struct 구조체 { // 값타입
var x = 10
mutating func doSomething() {
기본클로저 {
x = 200 /// Ok (암시적으로 self참조)
}
// ❌ 에러 발생
탈출클로저 {
self.x = 100
}
}
}
- 값 타입의 self 일경우 항상 암시적으로 self를 참조
- 위의 예시에서 doSomething 함수 내부에서 탈출 클로저를 호출하는 것은 오류다.
- mutating 함수 스코프에서 변수값을 바꾸는게 아닌 탈출클로저로 인해 외부 스코프에서 구조체(값타입)에 대해
변경하는 것이기 때문에 잘못된 사용이다.
참고
'프로그래밍언어 > swift' 카테고리의 다른 글
Dynamic Key decoding (2) | 2024.12.21 |
---|---|
GC vs ARC (1) | 2024.12.13 |
swift 기본 타입 (0) | 2024.10.18 |
디스패치 학습하기 (4) [ Extension Dispatch ] (0) | 2024.08.26 |
디스패치 학습하기 (3) [ Value Type Dispatch, Protocol Dispatch ] (0) | 2024.08.25 |