swift의 기본기라고 할 수 있는 [waek self]
를 빠른 작업이라는 미명하에 공부를 하지 않고 있었다.
이번에 언제 선영참조로 인한 메모리누수가 발생하는건지 알아보기로했다.
self가 클로져를 강한 참조하고, 클로져가 self를 강한 참조하면 선형회귀가 발생한다.
이를 예제 코드로 표현하면
class DummyClass {
var closure: (() -> Void)? = nil
var dummyVariable = 1
func dummyFunc() {
closure = {
print(self.dummyVariable)
}
closure()
}
}
위의 경우 서로 강한 참조를 하고있으므로 메모리누수가 발생한다.
하지만 아래의 경우, 클로저는 self를 강한 참조를 하고 있지만 클로저의 생명주기는 클로저가 실행 될때까지만 유지되므로 선형회귀가 발생하지 않는다.
class DummyClass {
var dummyVariable = 1
func dummyFunc() {
let closure = {
print(self.dummyVariable)
}
closure()
}
}
DispatchQueue
를 사용하여 강한참조 self를 사용할 경우를 시뮬레이션해보자.
class DummyClass {
var dummyVariable = 1
func dummyFunc() {
DispatchQueue.global().asyncAfter(deadline: .now + 10) {
print(self.dummyVariable)
}
}
}
만약 DummyClass 인스턴스가 살아있을 때 dummyFunc함수를 실행하고 클래스의 변수를 없애버린다면 어떻게 작동할까?
DispatchQueue 클로져 내부에서 self를 강한참조하고 있으므로, 10초 이후에 클로져가 실행된 이후에야 DummyClass 인스턴스는 해제될 것이다.
아래처럼 weak self을 이용해 retain을 증가시기지 않는다면:
class DummyClass {
var dummyVariable = 1
func dummyFunc() {
DispatchQueue.global().asyncAfter(deadline: .now + 10) { [weak self] in
guard let self else { return }
print(self.dummyVariable)
}
}
}
10초 후에 클로져안에 들어오게 되지만, guard let에 의해 return으로 빠져나가게 된다.