Weekoding

[Swift] weak self, guard let self = self, self?. 본문

공부 노트(Swift)

[Swift] weak self, guard let self = self, self?.

Weekoding 2022. 6. 6. 17:39

클로저를 사용할 때, [weak self]를 사용하게 된다.

그리고 때때로, 클로저 안에 guard let self = self로 self 캡처를 하는 경우를 보았을 것이다.

{[weak self] in
  guard let self = self else {return}
  ...  
}

오늘은 이것들에 대해서 파헤쳐 보고자 한다.

 

🔍 시작하기 전에: 

   capture: 클로저 내부에서 밖에 있는 scope의 instance를 참조하는 것

   escaping: 클로저 외부에서 해당 클로저 자체를 참조하고 있는 것

 

 

 

1. [weak self]

  : 약한 참조(weak reference)를 의미한다.

    써도 그만 안써도 그만일 것 같은 느낌이 드는데, 자세히 알아보자!

 

  1) [weak self]를 쓰는 이유는?

  Swift는 ARC(Automatic Reference Counting)이라는 것을 사용하는데,

  추후에 포스팅 할 예정이지만 간단히 말해서 메모리 관리를 자동적으로 해주는 녀석이다.

 

  ARC를 통해 대부분의 참조 문제들은 자동으로 해결된다.

  그러나 만약 두 개 이상의 객체가 서로에 대해 강한 참조(strong reference)를 갖게 된다면,

  순환 참조(Retain Cycle)라는 것이 발생한다. 참조 했었던 인스턴스가 nil이 되더라도,

  서로를 놓아주지 않아 계속 메모리를 차지하여 낭비하게 되는 것이다.

 

  이는 Memory leak을 초래하고, 결국 App의 Out of Memory라는 결과로 이어진다.

  따라서 이런 strong reference를 피하기 위해 [weak self]를 이용하는 것이다.

 

  2) [ weak self ]를 언제 써야할까?

  [weak self]는 Closure를 사용할 때 쓰인다.

  Closure가 실행되는 타이밍에 따라 사용방법에 차이가 있다.

 

  Non-escaping Closure: 범위(scope) 내에서 즉시 실행되는 클로저를 의미한다.

  - self가 클로저보다 먼저 dealloc되는 경우에 [weak self]가 필요하다. 그렇지 않으면 참조하는 순간 크래쉬가 발생할 수 있다.

 

  Escaping Closure: 다른 클로저로 전달되거나, 저장되거나, 다른 시점에 실행될 수 있는 클로저를 의미한다.

  - 강한 참조가 걸릴 수 있어 Escaping Closure를 사용할 땐 [weak self]가 필요하다.

  

⌘ 그래서 [weak self]는 클로저를 쓸 때 사용되는 코드라는 점!

 

 

 

 

2. guard let self = self 그리고 self?.

[weak self]를 쓰게 되면, 약한 참조인 만큼 self는 Optional이 된다.

이때, guard let self = self 뿐만 아니라, self?.라는 방법도 존재한다.

 

  1) guard let self = self

  : (클로저 내부에서)외부 프로퍼티를 캡처할때,

    현재 instance가 heap에 존재 → 객체를 strong reference로 참조

    현재 instance가 해제 → nil return 후 탈출.

 

  특징은 strong reference로 참조하는 데에 있다.

  완벽한 [weak self]에 대한 대처법이 아니라, 위험 요소도 있다는 의미이다.

 

  guard let self = self로 캡처한 self는 클로저가 종료될 때까지 참조가 해제되지 않는다.

  클로저 내에서 오래 걸리는 작업을 할 때, 원래라면 도중에 참조가 해제되어 작업이 끊길 우려가 있는데

  guard let self = self는 strong reference이기 때문에,

  클로저가 종료될 때 까지 메모리 지연 해제(deallocation delay)를 발생시킨다.

 

  강한 참조를 갖고 해제를 지연시키기 때문에, 중간에 무거운 작업을 수행될 때 크래쉬가 날 수 있다. 

 

2) self?.

  : (클로저 내부에서)외부 프로퍼티를 캡처할때,

    self instance가 존재한다면 해당 문장을 실행하고, 그렇지 않다면 넘어가는 코드.

 

  self?. 가 있는 문장마다 self가 nil인지를 체크하게 된다.  

  self가 메모리에서 해제되면, self?.로 이루어진 문장들은 실행되지 않는다.

  instance 참조가 해제 된 뒤에 불필요한 작업이라면 self?.를 이용하는것이 위험 부담이 적고 효율적이다.

 

 

 

정리 📌

[weak self]는 클로저를 사용할 때, strong reference로 인한

memory leak을 대처하기 위해 사용되는 코드이다.

 

weak self를 사용하게 되면 self instance가 Optional이 된다.

따라서 nil 여부를 체크(=캡처가 되었는지)해야 하는데,

이 때 필요에 따라 guard let self = self나 self?.중 하나를 사용하게 된다.

 

 

 

 

오류 및 지적사항은 댓글로 남겨주시면 감사하겠습니다!

참고 : 

https://ios-development.tistory.com/926

https://jinsangjin.tistory.com/129

Comments