ARC 2탄 느낌으로 낋여본다
class로만 순환참조 예제를 보다가 클로저랑 캡처리스트에서 순환참조가 이해가 안되어 하는 정리!
✅ 클로저도 객체다
// Dog 예제
var dog1: Dog? = Dog(name: "멍멍이") // 힙에 Dog 객체 생성
var dog2: Dog? = dog1 // 같은 객체 참조
// 클로저 예제 (동일한 원리!)
var completion: (() -> Void)?
let myClosure = { print("Hello") } // 힙에 클로저 객체 생성
completion = myClosure // 같은 클로저 객체 참조
-> 클로저도 힙에 생성되는 실제 객체이고, 변수들은 그 주소를 가리킨다!
✅ 캡처(Capture)란?
1. 캡처가 발생하는 정확한 순간
// ViewController.viewDidLoad() 내부
asyncFunction {
self.label.text = "Complete" // 이 순간 캡처!
}
2. 캡처의 본질
// 실제로 일어나는 일 (개념적)
// 원본 코드:
{ self.doSomething() }
// Swift가 내부적으로 생성하는 것:
class 자동생성된클로저 {
let 캡처된self: ViewController // 🚨 이것이 핵심!
init(원본self: ViewController) {
self.캡처된self = 원본self // 참조 카운트 +1
}
}
// 결국 이것과 동일:
let myViewController = self // 참조 카운트 +1
-> 클로저는 사용하는 외부 변수를 "납치해서 내부 프로퍼티로 저장"
✅ 순환 참조의 발생 과정
1. 순환 참조가 만들어지는 과정
var completion: (() -> Void)? // 전역 변수
func asyncFunction(_ completionHandler: @escaping () -> Void) {
completion = completionHandler // 같은 클로저 객체 참조
}
// ViewController에서:
asyncFunction {
self.label.text = "Complete" // self 캡처!
}
2. 메모리 관계도
ViewController → completion → 클로저객체 → self → ViewController
↑__________________________________________________|
순환 참조 완성! 🔄
✅ 해결책: weak self
1. 올바른 패턴
asyncFunction { [weak self] in
guard let self = self else { return }
self.label.text = "Complete"
}
2. 해결된 참조 관계
ViewController → completion → 클로저객체 → weak self (참조카운트 증가 안함)
↓
ViewController
'Swift' 카테고리의 다른 글
[Swift] Result 타입 (1) | 2025.06.17 |
---|---|
[Swift] Any와 AnyObject (0) | 2025.06.12 |
[Swift] 고차함수 더 이상 헷갈리지 않기 (0) | 2025.06.04 |
[WWDC] ARC in Swift (0) | 2025.05.30 |
Struct 접근제어와 Memberwise Initializers (0) | 2025.05.29 |