Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
Tags
- Clean Code
- Refactoring
- ribs
- 애니메이션
- 리펙터링
- RxCocoa
- tableView
- Protocol
- ios
- Observable
- collectionview
- 클린 코드
- HIG
- SWIFT
- Xcode
- 리펙토링
- swiftUI
- map
- UITextView
- combine
- swift documentation
- 리팩토링
- uiscrollview
- 스위프트
- rxswift
- uitableview
- MVVM
- Human interface guide
- UICollectionView
- clean architecture
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 2. weak self 동작 이해하기 - 외부에 weak self 선언하고 클로저에서 사용하는 경우 (#캡처리스트 [weak self] 리펙토링) 본문
Refactoring (리펙토링)
[iOS - swift] 2. weak self 동작 이해하기 - 외부에 weak self 선언하고 클로저에서 사용하는 경우 (#캡처리스트 [weak self] 리펙토링)
jake-kim 2023. 11. 5. 01:191. weak self 동작 이해하기 - retain cycle이 발생하는 경우
2. weak self 동작 이해하기 - 외부에 weak self 선언하고 클로저에서 사용하는 경우 (#캡처리스트 [weak self] 리펙토링)
weak self를 클로저 외부에서 사용 시 retain cycle이 발생할까?
- 예제를 위해 retain cycle이 발생하는 코드 준비
class A {
private var closureEscaper: ((String) -> ())?
func escape(closure: @escaping (String) -> ()) {
print("escaping!")
closureEscaper = closure
}
}
class B {
var name = "Jake"
let a = A() // 1. B에서 A참조
init() {
// 클로저 내부에서 strong self 참조: retain cycle 발생 o
a.escape { string in
self.name = string // 2. A에서 B참조
}
}
deinit {
print("DEINIT: B")
}
}
- 여기서 B인스턴스를 만든 후 nil을 할당해도 메모리 해제 x
var b: B? = B()
b = nil
// deinit이 안불림
- 외부에서 weak self 선언 시 retain cycle이 발생하지 않아서 b인스턴스는 deinit 호출
weak var weakSelf = self
a.escape { string in
weakSelf?.name = string
}
var b: B? = B()
b = nil
/*
escaping!
DEINIT: B
*/
- 외부에서 weak self한 후 옵셔널 바인딩: strong self로 다시 참조하므로 retain cycle 발생 o
weak var weakSelf = self
guard let weakSelf else { return }
a.escape { string in
weakSelf.name = string
}
// deinit이 안불림
weak self 리펙토링
- 하나의 함수 안에서 closure가 있는 함수를 사용하는 곳이 여러개가 있어, weak self를 다수 쓰는 경우가 존재
class ViewController: UIViewController {
var someValue = 0
override func viewDidLoad() {
super.viewDidLoad()
someFunc1 { [weak self] in
print(self?.someValue)
}
someFunc2 { [weak self] in
print(self?.someValue)
}
someFunc3 { [weak self] in
print(self?.someValue)
}
}
func someFunc1(block: @escaping () -> ()) {
// Some working...
}
func someFunc2(block: @escaping () -> ()) {
// Some working...
}
func someFunc3(block: @escaping () -> ()) {
// Some working...
}
- [weak self]를 매번 선언해주어도 되지만, 코드 중복으로 인해 외부에 weak self를 선언하여 사용해도 retain cycle없이 사용이 가능
- weak self를 매번 선언해주지 않아도 아래처럼 간결하게 처리가 가능
weak var weakSelf = self
someFunc1 {
print(weakSelf?.someValue)
}
someFunc2 {
print(weakSelf?.someValue)
}
someFunc3 {
print(weakSelf?.someValue)
}
주의사항) weak로 잡은 상태에서 옵셔널 바인딩하는 경우
- 보통 클로저 안에서 아래처럼 옵셔널 바인딩을 수행
someFunc1 { [weak self] in
guard let self else { return }
print(someValue)
}
- 하지만 외부에 weak self를 선언한 상태에서 다시 옵셔널 바인딩을 시도하면 strong self로 잡히는 것을 주의
weak var weakSelf = self
guard let weakSelf else { return } // <- strong self로 잡히므로 이 weakSelf를 closure안에서 쓰면 retain cycle
someFunc1 {
print(weakSelf.someValue)
}
someFunc2 {
print(weakSelf.someValue)
}
someFunc3 {
print(weakSelf.someValue)
}
핵심 정리
- 1). 클로저 내부에서 strong self 참조: retain cycle 발생 o
a.escape { string in
self.name = string
}
- 2). 외부에서 weak self: retain cycle 발생 x
weak var weakSelf = self
a.escape { string in
weakSelf?.name = string
}
- 3). 외부에서 weak self한 후 옵셔널 바인딩: strong self로 다시 참조하므로 retain cycle 발생 o
weak var weakSelf = self
guard let weakSelf else { return }
a.escape { string in
weakSelf.name = string
}
* 전체 코드: https://github.com/JK0369/ExWeakSelf
'Refactoring (리펙토링)' 카테고리의 다른 글
[Refactoring] 메서드와 함수의 파라미터 리펙토링 (0) | 2023.11.19 |
---|---|
[iOS - swift] 표현식을 이용한 조건문, 삼항 연산자, switch - enum 리펙터링 (Swift5.9) (3) | 2023.11.10 |
[iOS - swift] guard문 잘 사용하기 (#guard문 사용 시 주의사항, #이중부정, #2중부정) (0) | 2023.10.31 |
[iOS - swift] 복잡한 조건문 리펙토링 (if, else, else if, guard 문) (2) | 2023.10.27 |
[Refactoring] 11-4 상속 리펙토링 (Wrapper 만들기) (0) | 2023.07.28 |
Comments