안녕하세요.
[weak self] 관해서 얘기가 좀 많은가 봐요..허헣...
아래 글에서 [weak self] 관련한 얘기들을 다뤄봤는데요,
클로저에서 [weak self] 사용할 때 주의할 점2
비슷한 내용이지만 관련된 글이 있어서, 한번 내용을 정리해볼까 합니다.
이전 글들을 보면, 클로저 또는 중첩된 클로저에서 retain cycle을 막기 위한 방법은 크게 3가지라고 볼 수 있을 것 같아요.
- self를 그냥 사용해서 strong reference가 걸리는 것을 막는다.
- self로 override 한다.
- strongSelf로 바인딩한다.
여기에 대한 추가 견해(?)라고 볼 수 있는 내용은 아래와 같습니다.
## 1. self를 그냥 사용해서 strong reference가 걸리는 것을 막는다.
모든 곳에서 self?.foo 처럼 사용하면 됩니다.
다만, block 중간에서 self가 언제든지 nil이 될 수 있다는 것을 인지하고 있어야 해요.
## 2. self로 override 한다.
클로저 블록 상단에서 guard let self = self else { return } 구문을 사용해서 strong & non-optional 하게 바꿔주는 것이에요.
하지만 이 방법을 사용할 경우, 아래처럼 중첩된 클로저의 inner 클로저에서 self를 그대로 사용하지 않도록 주의해야 합니다.
(inner 클로저에서 self를 그대로 사용할 경우 retain cycle이 발생하기 때문이에요.)
self.doSomething = { [weak self] in
guard let self = self else { return }
self.doSomethingElse = { // inner 클로저에서 [weak self]를 사용하지 않을 경우, retain cycle이 발생합니다.
self.foo()
}
}
self.doSomething()
SwiftLint를 사용해서 이런 문제를 미연에 방지할 수 있겠죠??
## 3. strongSelf로 바인딩한다. 🤔
결론 먼저 말씀드리면, 선호하지 않는다는 얘기가 많아요.
guard let strongSelf = self else { return } 구문을 사용하면, 강한 참조인 strongSelf와 약한 참조인 self?를 block 안에서 자유롭게 사용할 수 있다는 장점은 있지만,
오히려 이게 더 헷갈리게 만든달까요??
아래 코드를 보면,
firstChild.playLater { [weak self] in
guard let strongSelf = self else { return }
strongSelf.gamesPlayed += 1
strongSelf.secondChild.playLater {
if let strongSelf = self {
// 👍 Locally bound the weak self reference.
// (But didn't use the bound variable.)
print("Played \(self?.gamesPlayed ?? -1) with first child.")
}
// ⚠️ Strongly captures `strongSelf` from outside by accident
// and creates cycle.
strongSelf.gamesPlayed += 1
completion(strongSelf.gamesPlayed)
}
}
inner 클로저에서 사용한 if let strongSelf = self { ... } 의 strongSelf와 strongSelf.gamesPayload + = 1 의 strongSelf는 서로 다른 것이에요.
strongSelf.gamesPayload += 1 의 strongSelf는 outer 클로저에서 선언한 strongSelf로, 지금 같은 구조라면 retain cycle이 생기게 됩니다.
## 결론
이러저러한 이유 때문에, [weak self] 사용에 대한 견해는 이렇게 정리가 될 것 같아요.
- non-escaping 클로저에서는 강한 참조인 self를 사용한다. (non-escaping 클로저에서는 retain cycle이 생기지 않기 때문입니다.)
- 애매하면... [weak self]를 쓴다.
- 클로저 상단에서 self로 override 한다.
## 참고
- https://christiantietze.de/posts/2022/05/weak-self-consistency/
이번 글은 여기서 마무리.
'Swift' 카테고리의 다른 글
inout (0) | 2022.06.05 |
---|---|
Modeling errors (0) | 2022.05.27 |
클로저에서 [weak self] 사용할 때 주의할 점2 (0) | 2022.04.24 |
클로저에서 [weak self] 사용할 때 주의할 점 (0) | 2022.04.16 |
Automatic Reference Counting (ARC) (0) | 2022.04.10 |