버그 잡이

swift - guard let self = self vs self?. 본문

Swift

swift - guard let self = self vs self?.

버그잡이 2020. 12. 8. 20:15

 

[weak self] 를 사용할 때, self를 처리하는 방법에는 두 가지가 있습니다.

'guard let self = self''self?.'

 

 

"무엇을 쓰는 것이 좋을까요?"

 

결론부터 말씀드리면 상황에 따라 다릅니다.

 

 

 

"guard let self = self"

 

먼저, 클로저 시작 부분에 'guard let self = self'를 쓰는 것은 "deallocation delay"를 발생시킬 수 있습니다.

deallocation delay 는 클로저가 참조하고 있는 객체의 메모리 해제를 지연시키는 현상을 말합니다.

클로저 안에서 이미지를 로드 하는 등의 시간이 오래 걸리는 작업이 있다면 클로저 안의 로직을 수행하는 도중에 self 인스턴스가 해제될 수 있는 것 입니다.

그런데 guard let으로 self 를 체크하면 self에 대한 강한 참조가 생기고 이후 클로저가 종료될 때까지 self의 해제를 지연시킵니다.

func process(image: UIImage, completion: @escaping (UIImage?) -> Void) {
    DispatchQueue.global(qos: .userInteractive).async { [weak self] in
        guard let self = self else { return }
        // perform expensive sequential work on the image
        let rotated = self.rotate(image: image)
        let cropped = self.crop(image: rotated)
        let scaled = self.scale(image: cropped)
        let processedImage = self.filter(image: scaled)
        completion(processedImage)
    }
}

위 코드를 예로 살펴보면,

guard let self = self 로 self 를 체크했기 때문에 클로저 안에서는 self에 대한 강한 참조가 생기고

self는 해당 클로저가 종료될때까지 메모리에서 해제되지 않습니다.

하지만 image 처리 관련된 무거운 로직이 실행되는 도중에 viewController는 언제든지 해제될 수 있습니다.

이때 viewController가 dismiss 되어도 클로저에서 강한 참조로 잡고 있기 때문에 클로저가 종료될때까지 viewController는 메모리에세 해제될 수 없습니다.

 

 

 

"self?."

 

반면 self?. 은 self?가 걸린 각 경우마다 self에 대한 nil 체크를 합니다. nil인 경우 해당 메서드를 스킵하고 다음 줄로 넘어갑니다.

func process(image: UIImage, completion: @escaping (UIImage?) -> Void) {
  DispatchQueue.global(qos: .userInteractive).async { [weak self] in 
      // perform expensive sequential work on the image
      let rotated = self?.rotate(image: image)
      let cropped = self?.crop(image: rotated)
      let scaled = self?.scale(image: cropped)
      let processedImage = self?.filter(image: scaled)
      completion(processedImage)
  }
}

클로저 내부 로직 실행 중에 self인 viewController가 dismiss 되면 self와 관련된 메서드는 skip 하고 넘어갑니다.

 

 

 

결론

 

사소한 차이일 수 있지만 이를 구분해서 쓰면

메모리 누수 또는 데이터 손상을 방지할 수 있습니다.

 

viewController 가 해제된 이후에 불필요한 작업이 진행되는 것을 피하고 싶다면 → self?.

반대로 객체가 해제되기 전에 모든 작업을 완료하고 싶다면 → guard let

 

 

 

*참고

https://medium.com/flawless-app-stories/you-dont-always-need-weak-self-a778bec505ef

반응형
Comments