RxSwift) DisposeBag() 정복하기 2

minin·2022년 5월 12일
1

RxSwift

목록 보기
2/2
post-thumbnail

# DisposeBag()

👩‍💻 새롭게 공부하며 작성한 글이기 때문에 틀린 정보가 있을 수 있습니다! 이에 대한 피드백은 언제나 환영입니다 🙌

🔗 DisposeBag() 정복하기 1편을 안보고 오셨다면 보고오기!

그럼 지금부터 DisposeBag()에 대해서 알아보겠습니다!

# DisposeBag()


정의를 살펴보면 DisposeBag은

  • deinit할 때, 배열에 추가되어있는 disposable들을 dispose하는 것이다!
  • Swift에서 메모리 자원을 관리하는 ARC의 RxSwift 버전이라고 할 수 있다.

disposed(by bag: DisposeBag)의 동작

그럼 우리가 자주 사용하는 RxSwift의 DisposeBag을 이해해 보자.

먼저, DisposeBag을 사용하는 이유를 통해, DisposeBag의 기능을 생각해 보면,

  • 왜 사용?
    → dispose해야 하는 disposable이 많아서, 배열에 담아서 쉽게 관리하려고
  • 어떻게 동작?
    1. subscribe를 통해 Disposable 리턴
    2. Disposable을 담을 수 있는 배열 [Disposable]에 리턴된 것을 담음
    3. deinit 되는 시점에 dispose() 해줌.

이를 기억하고 있다면! 다음에 오는 내용을 쉽게 이해할 수 있을 것이다.

1. extension Disposable


프로토콜 Disposable을 확장한 곳에는, disposed(by:)라는 함수가 있다.

이것은 바로, 우리가 자주 보던 그것임.

let disposeBag = DisposeBag()
Observable.of(1, 2, 3)
    .subscribe{
        print($0)
    }
    .disposed(by: disposeBag)

이거이거.. 익숙하지요?

위의 Disposable의 함수를 보면, bag.insert(self)라는 것이 들어잇음. 그럼 이건 뭐게?

DisposeBag에 들어있는 무언가 이겠지요.

insert(self)라는 함수의 이름으로 보아서 bag에 추가해 주는 것이겠고, self는 Disposable이니까!

아마도 disposable들이 담겨져 있는 배열에 추가해 주는 것은 아닐까..? 하는 합리적 의심을 할 수 있음.

2. DisposeBag

이제 아까 잠시 살펴본 DisposeBag으로 돌아와보자.

  • 먼저 여기에서는 disposables라는, 우리가 말한 Disposable들을 담을 배열을 가지고 있음.
  • 그리고 isDisposed라는 지금은 알 수 없지만 해제되었는지 아닌지를 판단하는 것처럼 보이는 파라미터를 가지고 있음. 앞으로의 내용 이해를 돕기 위해 먼저 정답을 말하자면, 이게 맞다. 해제되었는지, 아닌지 판단하는 것!
  • cf. lock

    잘은 모르겠지만, 설명을 읽어보니 thread-safe하게 만드는 방법에서 나왔던 내용 같다. 멀티쓰레딩을 할 때 자원이 변경하는 도중에 다른 곳에서 접근할 수 없도록 막아두는 것.

insert()

그리고 조금 더 내려가면, DisposeBag이 가지고 있는 함수들을 만날 수 있는데

짜잔, 아까 본 insert를 바로 만났다.

먼저 self.lock.performLocked는 우선 값의 변경이 끝나기 전에 외부에서 접근하지 못하게 막는 것이라고 생각하고 넘어가자.

그리고 아래를 살펴보면, isDisposedtrue이면, disposable을 리턴하고,
아니면 disposables에 추가함.

앗! 글쿤. (?

자,

  • isDisposable 이니? = deinit 호출되는 타이밍이니? ⇒ disposable리턴 (얘는 dispose()될 운명임)
  • isDisposable 아니니? = deinit 호출되는 타이밍 아니니? ⇒ disposables 배열에 추가.

앞의 내용을 이해하면서 따라왔다면, 쉽다!

public func insert(_ disposable: Disposable) {
        self._insert(disposable)?.dispose()
}

insert(_:) 함수에서
_insert(disposable)?의 결과가 있으면(nil이 아니면) dispose()를 시켜서 메모리를 정리한다.

근데 dispose()가 대체 먼데.. 너 그거 머냐..그래서..먼데..
insert(_:) 함수로부터 반환된 Disposable 타입 프로토콜의 요구사항인 func dispose()에 접근하는 것인데,
이놈이 어디에 구현되어 있는지 모르겠다...
👉 우선은, dispose()라는 것이 모든 옵저버와 리소스들의 구독을 취소하는 역할을 한다는 점을 알고, 넘어가도록 하자.

dispose()

그 다음에 알아볼 것은 disposeBag이 deinit되는 시점에 호출되는 dispose()입니다!
이는 disposeBag이 메모리에서 내려갈 때에 자동으로 호출되어 더이상 사용하지 않는 리소스들을 정리하고 메모리 누수를 막을 수 있도록 기능을 하는 것입니다.
자세히 살펴 볼까요?


let oldDisposables = self._dispose()
아.. 이건 또 머지요? 살펴봅시다.

먼저 위의 파라미터를 이해하기 위해서 _dispose() 를 보면, 일단 [Disposable]을 리턴하는 것.

self.lock.performLocked 이거 살포시 패스하고...(쓰레드에 접근 못하게 막아주고)

  • 먼저 disposables를 새로운 변수에 저장해두고,
  • 기존에 가지고 있던 disposables 배열 안을 싹 비우고, isDisposedtrue 만들어줌.
  • 그리고 아까 저장해놨던 disposables를 리턴함. (방금 비운거 말고, 기존의 disposables를 리턴)

그리고 dispose()함수로 돌아가서,

  • oldDisposables, 즉 원래의 disposables의 내부에 있는 disposable들을 순회하면서,
  • dispose()를 통해 메모리에서 내려준다!

이해 가셨나요?

결국은 disposeBag() 클래스 인스턴스에 있는, 지워져야햐는 대상 목록이 비워지고, 실제로 메모리에서도 해제되는 것입니다!

이제 DisposeBag에 대해서 이해가 가셨기를!

그럼 2000...(우와진짜 옛날사람

🔖 참고

profile
🍫 iOS 🍫 Swift

0개의 댓글