-
weak self 에 대해서 (언제나 하는걸까?)Swift 2021. 6. 18. 16:26
메모리 누수를 막기 위한 weak self는 언제 써야되는것일까?
일단 아래 얘기를 하고 싶어서 쓰게되었다. (You don't always need [weak self])
하지만 결론은 아니다.
https://medium.com/flawless-app-stories/you-dont-always-need-weak-self-a778bec505ef
위의 글에서 핵심인 내용은
For example, none of these calls will cause a memory leak, even without [weak self], because they are executed immediately:
위의 문장이다. 바로 끝나기때문에 아무것도 메모리릭을 발생시키지 않아.
즉 언제 해야하냐?
class PresentedController: UIViewController { var closure: (() -> Void)? } class MainViewController: UIViewController { var presented = PresentedController() func setupClosure() { presented.closure = printer } func printer() { print(self.view.description) // 바로 이런 부분임...!! self를 closure에 캡쳐해서 복사됨 // 그럼 main도 presentedController를 소유, presented도 main을 소유 } } // 따라서 이럴때 아래처럼 바꾸어야함! func setupClosure() { self.presented.closure = { [weak self] in self?.printer() } }
// 위의 글에 나와있지만, 바로 실행시키는 경우의 예시로 나와있는 부분이다. 이런건 강한 참조가 일어나지 않는다. func setupAnimation() { let anim = UIViewPropertyAnimator(duration: 2.0, curve: .linear) { self.view.backgroundColor = .red } anim.addCompletion { _ in self.view.backgroundColor = .white } anim.startAnimation() }
결론!!
closure가 self를 강하게 참조 하면서 클로져 실행이 끝나기 전까지 self는 메모리에서 해제되지 않는다.
= 이말은 실행이 바로 끝나는애는 강한참조를 발생시키지않는다!
하지만 article을 꼼꼼하게 읽어보면,
escaping closure와 달리 Non-escaping closure는 범위(scope) 내에서 실행된다. 즉, 코드를 즉시 실행하고 나중에 저장하거나 실행할 수 없다.
+ (예: compactMap과 같은 고차 함수)는 강력한 참조 주기를 도입할 위험이 없으므로 weak 또는 unowned를 사용할 필요가 없다.
그러나!
Delayed Deallocation는 Escaping 및 Non-escaping 클로저에서 나타나는 부작용이다. 정확히 메모리 누수는 아니지만 원하지 않는 동작으로 이어질 수 있다.
이 경우 Escaping 및 Non-escaping 클로저 모두 [weak self]를 사용해 Delayed Deallocation를 방지할 수 있다.
그러니까 메모리 릭을 발생시키지 않아도 써주는게 좋은것이죠~~
하지만 몇가지 고려사항이 또 있어요...ㅎㅎ
Delayed Deallocation가 나타날 수 있는 클로저에서 'guard let self = self' 구문을 사용한다면 Delayed Deallocation를 방지할 수 없는데요...
클로저 수명동안 self가 유지되도록 보장하기 때문인데 따라서 self?. optional chaining을 고려해해서 사용해야합니다!
+ 특수한 경우가 있을 수 있죠. 바로 singleton 인데요...!! self가 원래! 해제되지 않는 경우라면 delayed deallocation도 쓸 필요가 없겠죠?
++
한국어로 쉽게 정리된 것이 있어서 추가한다. 이해가 되지 않는 부분은 아래를 좀 참고했다...ㅎ_ㅎ
https://velog.io/@haanwave/Article-You-dont-always-need-weak-self
++
DispatchQueue.main.async { self.tableView.reloadData() } // 위의 글을 맞게 이해했다면 이건 weak self로 할 필요는 없다. 아래의 stackoverflow도 추가한다.
https://stackoverflow.com/questions/65525275/weak-self-in-gcd-accessing-tableview-property-of-self
위의 구문만 보고서는 그렇지만, 실제로 동작할때 해당 self가 해당 view라면 그 view가 메모리에 갑자기 해제된다면 reload가 모두 끝난 뒤에야 self가 해제될테니 (강한 참조 중이니까) 약간의 delay 가 있을 수 있다는 점을 애니메이션과 위 같은 경우에도 고려할 수 있습니다.
즉, 꼭 해야할 필요는 없고 (메모리 누수 없음!, unsafe 한 개념이 아님!) delayed deallocation을 고려해서 작성한다면
DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() }
RxSwift의 경우는 또 다른 경우의 문제가 있다~~
https://www.youtube.com/watch?v=687KaKJ8B7U
위의 영상은 subscribe 할때 self를 복사해서 저장하는데, 이때 해당 viewcontroller가 count가 2로 남게 되어 제거되지 않는 경우를 말한다.
https://stackoverflow.com/questions/35003355/weak-self-in-rxswift-closures
728x90'Swift' 카테고리의 다른 글
Swinject 사용, DI란? (0) 2021.06.30 xcode 오류 nw_connection_copy_protocol_metadata [C20] Client called nw_connection_copy_protocol_metadata on unconnected nw_connection (0) 2021.06.29 Operation Queue (0) 2021.05.26 컴파일 타임 / 런타임 (0) 2021.05.12 Swift GCD (0) 2021.05.11