본문 바로가기
Swift

[Swift] closure 내부의 weak self 사용

by Sky Titan 2022. 4. 3.
728x90
 

[iOS - swift] weak self 알고쓰기 (escaping closure, memory leak, weak self를 사용해도 crash가 나는 이유)

사전 지식1) capture와 escaping의 개념 공통점: 둘 다 closure에서 사용되는 개념 차이점 capture: 클로저 내부에서 밖에 있는 scope의 instance를 참조하는 것 escaping: 클로저 외부에서 해당 클로저 자체를 참

ios-development.tistory.com

 

 

You don’t (always) need [weak self]

We will talk about weak self inside of Swift closures to avoid retain cycles & explore cases where it may not be necessary to capture self weakly.

medium.com

escaping closure의 의미

  • 인자로 전달받은 closure 중 함수의 종료 이후에 실행될 수 있는 closure
  • 저장, 지연될 수 있는 기능 블록을 가지는 closure가 바깥의 변수에 의해 저장되는 경우엔 escaping closure로 정의한다.
  • 필요한 이유:
    • 컴파일러의 최적화 때문
    • non-escaping closure의 경우, closure가 언제 실행되고 종료되는지 알기 때문에, closure안의 객체들의 life cycle을 컴파일러가 관리하기가 용이하다. 그래서 optional로 필요한 경우에만 escaping을 명시적으로 사용할 수 있게 한다.

https://jusung.github.io/Escaping-Closure/

 

[Swift] Escaping 클로저 (@escaping)

정의 Escaping 클로저는 클로저가 함수의 인자로 전달됐을 때, 함수의 실행이 종료된 후 실행되는 클로저 입니다. Non-Escaping 클로저는 이와 반대로 함수의 실행이 종료되기 전에 실행되는 클로저

jusung.github.io

guard let strongSelf = self 사용 시 주의

  • [weak self] 를 이용해서 클로져 내부에서 self를 weak 레퍼런스로 캡쳐하여도 guard let strongSelf = self 를 통해 강한 참조를 하는 순간 self의 reference count는 증가한다.
    • 다만, weak self로 캡처를 하였으면 closure가 종료되면 count는 감소한다.
    • weak self로 캡처를 하지 않고 closure내부에서 self를 강한 참조로 사용하면 closure가 종료되어도 count가 감소하지 않아서 self가 dealloc이 되지 않을 수도 있다.
    • strongSelf 사용 시 적어도 클로저가 종료되기 전까지는 self가 메모리 해제되지 않음을 보장할 수 있다.
class Test {
    
    lazy var closure: (() -> Void)? = { [weak self] in
        print("weak \(CFGetRetainCount(self))") // weak 2
        guard let strongSelf = self else { print("nil")
            return }
        print("strong \(CFGetRetainCount(strongSelf))") // strong 3 : 강한 참조로 인해 증가
        strongSelf
    }
}

var test: Test? = Test()
print("init \(CFGetRetainCount(test))")
test?.closure?()
print("after closure \(CFGetRetainCount(test))") // 클로저 종료되면서 strongSelf에 대한 참조 감소

/*
init 2
weak 2
strong 3
after closure 2
*/

 

closure내부에서의 weak self 사용

  1. escaping closure인 경우
    • 무조건 weak self를 사용해야함
  2. escaping closure가 아닌 경우
    • self가 closure보다 늦게 dealloc되는 경우 → weak self 사용할 필요 x
    • self가 closure보다 일찍 dealloc되는 경우 -> closure에서 self를 참조하는 순간 크래시 발생 -> weak self 사용 필요

 

728x90

'Swift' 카테고리의 다른 글

[Swift] closure에서 self를 써야하는 이유  (0) 2022.05.16
[Swift] 캡처리스트 (Capture List)  (0) 2022.04.05
[Swift] allSatisfy(_:)  (0) 2022.03.28
[Swift] Extension에 storedProperty 선언하기  (0) 2022.03.26
[Swift] Property Wrapper  (0) 2022.02.13

댓글