일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- DispatchQueue
- Xcode
- 옵저버패턴
- 싱글턴패턴
- ViewController
- 디자인패턴
- Scenedelegate
- 프록시패턴
- 데코레이터패턴
- 파사드패턴
- 스트래터지패턴
- 이터레이터패턴
- 템플릿메서드
- Lifecycle
- SWIFT
- 스테이트패턴
- WKWebView
- 컴포지트패턴
- 전략패턴
- 컴파운드패턴
- 추상팩토리패턴
- 팩토리메서드패턴
- 어댑터패턴
- unowned
- 커맨드패턴
- 상태패턴
- ios
- RxSwift
- Mobile
- cocoapods
- Today
- Total
ios dev kangwook.
iOS) Closure 내 [weak self] : guard let self vs. self?(optional chaining) 본문
iOS) Closure 내 [weak self] : guard let self vs. self?(optional chaining)
kangwook 2022. 8. 18. 23:05iOS 개발자로써 항상 고민되는 것이 있다.
Closure 내에서 self를 캡쳐할 때 [weak self]를 사용할 경우
guard let self = self 를 써야할까? 아니면 self?.(Optional Chaining)를 써야할까?
이에 대해 확실하게 공부할겸 정리를 해야겠다.
[weak self]
closure를 쓸 때 종종 우리는 [weak self]를 써야하는 순간이 오곤 한다.
이걸 왜쓰냐!
self를 사용할 때 순환참조로 인한 메모리릭을 방지하기 위해서 쓰는 거다.
근데 이걸 언제 쓰냐면 escaping 클로저 내부에서 delay deallocation 발생할 경우에 쓴다.
예를 들면 비동기 처리를 한다던가(API 등).. 타이머라던가..
정확하게 알고싶으면 아래 참조의 링크를 들어가보는 것이 좋다.
링크에 들어가면 이러한 그림이 먼저 나오는데 weak self의 사용에 대해 깔끔하게 정리한 것 같아서 첨부한다.
이를 기준으로 어느정도 판단하면 될 것 같다.
guard let self = self else { return }
self(주로 ViewController)가 클로저가 종료되기 전까지 해제되지 않는다.
예를 들어 클로저 내부에서 이미지 업로드 같이 오래 걸리는 작업을 실행할 경우, 해당 작업들이 끝나기 전까지 self가 해제되지 않는다.
객체가 해제되기 전에 모든 작업을 끝내고 싶은 경우에 적절하다!
self?.(Optional Chaining)
self(주로 ViewController가 해제되면 해당 구문은 실행되지 않는다.
ViewController가 해제됨과 동시에 해당 구문들이 실행되지 않으므로 예를 들어 이미지를 로드하는 구문이 클로져 내부에 있었다면 ViewController가 해제되고 나면 해당 작업을 실행할 필요가 없으므로 이러한 상황에 적절하다.
뭐 하지만 사실상 stackoverflow를 찾아봐도 그렇고 실질적으로 거의 동일한 역할을 하기 때문에 (엄청 크게) 구분을 지어서 사용하지는 않아도 된다고 한다.
(나는 사실 guard let self = self 를 주로 사용하는 편이다.)
뿐만 아니라 DispatchQueue같은 GCD, animate 같은 클로저에서는 순환참조가 일어나지 않기 때문에 weak self를 캡쳐리스트에 넣지 않아도 된다.
Closure가 중첩되어 있다면?
그럼 만약에 Closure가 중첩되어 있으면 어떻게 사용해야 할까?
결론적으로 말하자면 사실 중첩되어 있는 클로저는 내부든 외부든 [weak self]와 guard let self = self else { return }을 한 번만 사용하면 컴파일러가 알아서 내/외부 클로져에 적용한다고 한다.
// ...
updateDownloadContent(currentData: downloadLecture, mediaContentKey: mediaContentKey) { // 여기에 weak self를 쓸 필요 없음
DispatchQueue.main.async{ [weak self] in
guard let self = self else { return }
// ...
}
}
// ...
또는
// ...
updateDownloadContent(currentData: downloadLecture, mediaContentKey: mediaContentKey) { [weak self] in
guard let self = self else { return }
DispatchQueue.main.async{ // 여기에 weak self를 쓸 필요 없음
// ...
}
}
// ...
아 그리고 위에서 DispatchQueue에서는 [weak self]를 사용하지 않아도 된다고 했는데, 경우에 따라서 escaping 클로져 내부에서 외부 클로저를 호출해야할 경우 DispatchQueue 클로저에서도 사용해야 할 경우가 있다.
추가적으로 [unowned self]에 대해서 얘기하려고 한다.
[unowned self]는 옵셔널을 피하기 위해 사용할 수 있지만 self가 nil이 되지 않는다고 확신할 수 있을 경우에만 사용해야 한다.
만일 self 가 nil이 된다면 앱이 꺼지거나 crash가 날 확률이 높다.
그러니까 그냥 weak self를 쓰도록 하자.
* 틀린 내용이나 오타 등 부족한 부분이 있으면 댓글 남겨주시면 감사하겠습니다.
참조
'iOS' 카테고리의 다른 글
iOS) Memory Management - ARC (0) | 2022.08.27 |
---|---|
iOS) App Life Cycle, View LIfe Cycle (0) | 2022.08.27 |
iOS) WKWebView vs. SFSafariViewController (0) | 2022.08.22 |
iOS) XCFramework를 생성해보자 (0) | 2022.08.20 |
iOS) CocoaPods에 Private Framework 추가하기 (0) | 2022.08.20 |