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
- MVVM
- 리펙토링
- ribs
- rxswift
- Human interface guide
- 스위프트
- UITextView
- uiscrollview
- collectionview
- uitableview
- UICollectionView
- tableView
- clean architecture
- combine
- 클린 코드
- Protocol
- HIG
- RxCocoa
- swiftUI
- ios
- SWIFT
- map
- Xcode
- Observable
- 리팩토링
- swift documentation
- Refactoring
- 리펙터링
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 1. weak self 동작 이해하기 - retain cycle이 발생하는 경우 (#클로저, #escaping 클로저) 본문
iOS 응용 (swift)
[iOS - swift] 1. weak self 동작 이해하기 - retain cycle이 발생하는 경우 (#클로저, #escaping 클로저)
jake-kim 2023. 11. 4. 01:351. weak self 동작 이해하기 - retain cycle이 발생하는 경우 (#클로저, #escaping 클로저)
2. weak self 동작 이해하기 - 외부에 weak self 선언하고 클로저에서 사용하는 경우 (#캡처리스트 [weak self] 리펙토링)
weak self 개념
- escaping closure에서 순환 참조를 발생시키는 케이스에서 캡쳐 리스트로 weak 참조를 사용
- 순환참조란?
- 생성자가 할당 해제된 후에도 인스턴스가 할당 해제되지 않도록 하는 reference 상 순환을 이루는 상태
- 둘 이상의 인스턴스가 서로에 대한 strong 참조를 보유할 때 발생
- 구체적인 내용은 이전 포스팅 글 참고
사전지식) 클로저란?
- Closure(폐쇄): 클로저는 코드에서 전달 및 사용할 수 있는 2가지의 자체 기능을 가진 블록
사전지식) @escaping 클로저란?
- 클로저의 실행이 지연되는 것
- 이름이 escaping인 이유) 한 예로 메서드의 블록에서 지역변수들을 선언하고 사용하면 해당 메서드의 블록 실행이 종료될 때 같이 사라지는데, 메서드의 실행 블록이 종료되어도 아직 클로저가 살아있으면 그 것들을 escaping이라 명명
ex1) closure 인수가 지연되지 않으므로 @escaping 키워드를 붙이지 않아도 가능
class A {
func escape(closure: (String) -> ()) {
closure("test")
}
}
ex2) 딜레이가 부여되는 동시에 @escaping을 붙이지 않으면 에러
ex3) 또 다른 delay의 의미로 property에 저장하는 경우에서도 역시 @escaping 을 붙이지 않으면 에러
- 즉 딜레이 되는 클로저가 발생하면 무조건 @escaping을 붙여야 사용이 가능
class A {
private var closureEscaper: ((String) -> ())?
func escape(closure: @escaping (String) -> ()) {
print("escaping!")
closureEscaper = closure
}
}
retain cycle이 발생하는 경우
- escaping 클로저에서 strong self로 참조했을때 무조건 retain cycle이 발생하지 않음
ex) esacping 클로저 준비
class A {
func escape(closure: @escaping (String) -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure("test")
}
}
}
class B {
var name = "Jake"
let a = A()
init() {
a.escape { string in
self.name = string
}
}
deinit {
print("DEINIT: B")
}
}
- 아래처럼 처리하면 "DEINIT: B"가 출력되면서 retain cycle이 발생하지 않은 것을 확인
var b: B? = B()
b = nil
// DEINIT: B
- 만약 closure를 property에 저장하는 escaping closure의 경우에 storng self로 처리하면 retain cycle이 발생
class A {
private var closureEscaper: ((String) -> ())?
func escape(closure: @escaping (String) -> ()) {
closureEscaper = closure
}
}
class B {
var name = "Jake"
let a = A()
init() {
a.escape { string in
self.name = string
}
}
deinit {
print("DEINIT: B")
}
}
var b: B? = B()
b = nil
// retain cycle때문에 "DEINIT: B" 호출되지 않음
- 여기서 알 수 있는 것: retain cycle은 @escaping에서 strong self로 잡아도 발생하지 않을 수 있음
정리
- 클로저는 코드에서 전달 및 사용할 수 있는 2가지의 자체 기능을 가진 블록
- escaping 클로저란 실행이 지연될 수 있는 클로저를 의미
- 중요사항
- retain cycle이 발생하는 경우는 escaping 클로저에서 weak self 안쓰면 발생한다? x
- retain cycle이 발생하는 경우는 escaping 클로저이고 이 closure가 또 다른 property에 저장될 때 발생한다? o
'iOS 응용 (swift)' 카테고리의 다른 글
Comments