저번 포스팅에서 순환 참조와 ARC에 대해서 알아보았다.
이제 이러한 순환 참조가 실제로 일어나는 예시에 대해 살펴보자
Clousuer
우리는 흔히 클로져 에 [weak self] 키워드를 쓰는 것을 알 수 있다!
이것을 왜 사용하는 지 알아보기 전에 "Closure Capture"라는 것에 대해 알 필요가 있다.
Closure Capture
Closure는 주변 Context로 부터 상수나 변수를 Capture할 수 있는데, 먼저 예제를 살펴보자!
func makeIncrementer(forIncrement amount: Int) {
var runningTotal = 0
let closure = {
runningTotal += amount
print(runningTotal)
}
closure()
closure()
}
해당 예시에서, runningTotal은 Closure 내부에 선언하지 않았지만,
사용할 수 있다!
이를 runningTotal이라는 변수가 Closure에 의해 Capture되었다고 한다.
또한, Value Type의 변수든, Reference Type의 변수든
Closure는 Reference Type으로 값을 캡처한다.
func makeIncrementer(forIncrement amount: Int) {
var runningTotal = 0
let closure = {
runningTotal += amount
print(runningTotal)
}
closure() // 10
closure() // 20
}
Value Type의 경우 해당 문제를 Capture List를 통해 해결할 수 있다.
Capture List
Capture List는 미리 Capture할 변수, 상수들을 명시적으로 표현하는 것이다.
func makeIncrementer(forIncrement amount: Int) {
var runningTotal = 0
let closure = { [runningTotal, amount] in
print(runningTotal)
}
closure() // 0
runningTotal = 10
closure() // 0
}
Value 타입의 경우는, Value type으로 값을 capture하지만,
"상수" 로 값을 캡처하게 된다.
let closure = { [runningTotal, amount] in
runningTotal += amount //Error!
print(runningTotal)
}
따라서, 해당 경우에 에러가 나게 된다.
Reference타입의 경우는, Referecne Type으로 값을 Capture한다.
또한 강한 참조로 값을 참조한다.
이는 Reference Counting이 증가하며, Closure로 인해 원하는 시점에서 인스턴스가 메모리에서 해제가 안될 수 있다.
즉! 메모리 누수가 발생한다.
저번 포스팅에서 보았듯이, 이는 weak 이라는 키워드로 해결을 하였는데,
이러한 이유 때문에 [weak self]를 사용하는 것이다.
Reference
'iOS > Swift' 카테고리의 다른 글
[Swift] Properties(2) - Wrappers, Type (0) | 2023.01.18 |
---|---|
[Swift] Properties(1) - Stored, Computed, Observer (0) | 2023.01.17 |
[Swift] Memory Leak(1) - 약한 참조, 강한 참조, unowned 참조 (0) | 2022.11.25 |
[Swift] Initializer(3) - required init?(coder:) (1) | 2022.11.10 |
[Swift] Initializer(2) - Class Initializer의 상속 (0) | 2022.11.10 |