weak self의 필요성

치킨치·2024년 6월 14일
0

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으로 빠져나가게 된다.

profile
풀스텍이었던 iOS개발자

0개의 댓글