-
RxSwift - DisposableProgramming/RxSwift 2022. 3. 17. 21:39
안녕하세요 BeePeach입니다 :)
오늘은 Disposable에 대해서 공부해보려고 합니다.
subscribe 오퍼레이터를 통해서 구독을 시작하면 Observable이 동작을 하게 된다고 공부를 했습니다.
그럼 이벤트 방출을 시작한 Observable은 언제 종료될까요??
Observable은 Error나 Completed 이벤트를 방출하게 되면 종료됩니다.
혹은 두 이벤트를 방출하지 않아도 dispose()를 호출하면 Observable이 종료됩니다.
Disposable
Disposable이란 사전적 의미는 "처리할 수 있는" 입니다.
Disposable를 이용해서 Observable과 Observer의 sequence를 끊고 Observable과 관련된 모든 리소스를 정리할 수 있습니다.
Disposable에 대해서 보니 protocol로 되어있고 요구메서드로 dispose() 오퍼레이터가 정의되어 있습니다.
모든 subscribe 오퍼레이터는 리턴 타입이 Disposable입니다.
즉 구독을 시작했다면 dispose() 오퍼레이터를 이용해서 Observable과 관련된 리소스를 정리할 수 있습니다.
그럼 of 오퍼레이터를 통해서 1 ,2 3을 차례대로 방출한뒤에 Completd 이벤트를 방출하는 Observable을 생성하고 구독을 해보겠습니다.
dispose() 오퍼레이터는 아직 호출하지 않았습니다.
그런데 결과를 보면 Disposed 됐다는 로그를 확인할 수 있습니다.
우린 분명히 dispose() 오퍼레이터를 호출하지 않았는데 왜 Disposed 됐다는 로그가 출력될까요??
그 이유는 Completed 이벤트가 방출되었기때문입니다.
나는 Completed 방출한 적 없는데..? 1, 2, 3만 방출하도록 했어!라고 할 수 있지만
우리가 이전에 공부했던 of, from, just 등의 오퍼레이터는 Next이벤트를 방출하고 자동적으로 Completed 이벤트를 방출합니다.
맨 위에서 Completed 또는 Error 이벤트가 방출되면 Observable이 종료된다고 했었죠??
꼭 dispose() 오퍼레이터를 호출하지 않아도 두 이벤트 중에 하나만 방출되어도 Observable은 메모리에서 해제됩니다.
하지만 그렇다고 dispose() 오퍼레이터는 빼먹는 것은 좋지 않습니다.
권장사항에서도 꼭 구독 후에는 dispose 해주는 것을 권장하고 있습니다.
심지어 subscribe 오퍼레이터의 리턴 타입인 Disposable을 사용하지 않았다는 컴파일러의 경고가 우리를 거슬리게 만듭니다.
그럼 한번 dispose() 오퍼레이터를 호출해보도록 하겠습니다.
마지막에 dispose()를 호출한 것을 볼 수 있습니다.
사실 변한 건 없지만 컴파일러의 경고도 사라졌습니다.
DisposeBag
그런데 이렇게 매번 dispose() 오퍼레이터를 호출하는 것보다 더 권장되는 방법이 있습니다.
바로 DisposeBag을 생성하고 여기에 담아두는 것입니다.
Disposebag이 메모리에서 해제될 때 한 번에 dispose()를 호출해서 메모리를 정리합니다.
사용방법은 매우 간단합니다.
DisposeBag 객체를 생성한 뒤에 subscribe 오퍼레이터를 호출하고 이후에 disposed(by:)를 호출하고 파라미터로 생성한 bag을 전달해주면 끝입니다.
그럼 알아서 알맞은 시점에 관련된 리소스가 메모리에서 해제됩니다.
여기서 말한 알맞은 시점이란 disposeBag을 소유한 인스턴스가 메모리에서 해제될때입니다.
프로젝트에선 주로 ViewController나 ViewModel class에서 프로퍼티로 disposeBag을 선언하므로 해당 class가 해제될때 disposeBag이 해제됩니다.
이렇게 Observable을 정의하고 subscribe로 구독후에 disposed(by:)를 이용하는 구조를 많이 사용하게 됩니다.
그런데 여기서 Disposed 됐다는 로그는 안 뜨네요??
이전 포스팅에서 설명했듯이 subsribe(_:) 오퍼레이터를 사용했기 때문입니다.
disposed는 Observable이 전달하는 이벤트가 아닙니다.
이전에 사용한 suvscribe(onNext:onError:onCompleted:onDisposed:) 오퍼레이터에서 Observable이 dispose 될 때 파라미터로 전달한 클로저가 실행되는 것뿐입니다.
원하는 시점에 dispose()를 호출하여 Observable 중지시키기
그리고 꼭 subscribe 오퍼레이터를 호출한 뒤에 dispose()를 호출해야 하는 것은 아닙니다.
내가 원하는 시점에 dispose()를 호출해서 Observable을 종료시킬 수도 있습니다.
예시를 보여드리겠습니다.
interval(_:scheduler:) 오퍼레이터는 일정 시간 동안마다 계속해서 이벤트를 방출합니다.
여기서 우리는 dispose()를 호출하지 않았습니다.
이 Observable은 영원히 1초마다 Next이벤트를 방출하게 됩니다.
그럼 여기서 우리가 했던 것처럼 subscribe 이후에 바로 dispose()를 호출하면 어떻게 될까요?
아무것도 방출하지 않고 바로 Disposed가 됩니다.
그런데 신기한 건 Completed 이벤트도 방출되지 않았습니다.
그 이유는 이 Observable이 정상적으로 Completed를 이벤트를 방출하고 종료된 것이 아니라 dispose()로 종료됐기 때문입니다.
이런 식으로 Observable을 참고하고 있다가 원하는 시점에 dispose() 시킬 수 있습니다.
그런데 이런 방식은 Completed 또는 Error 이벤트를 방출하지 않기 때문에 잘 사용되는 방식은 아닙니다.
사용 이유
Disposable을 사용하는 이유는 메모리 누수 때문입니다.
Observable과 관련된 리소스를 모두 해제시켜서 메모리 누수가 발생하지 않게 해 줍니다.
만약에 깜빡하고 빼먹었다면?? 컴파일러가 경고로 빼먹었다고 알려주므로 걱정하지 않아도 됩니다.
create 오퍼레이터
여기까지 이해하셨다면 이전 포스팅에서 공부했던 create 오퍼레이터에 대해서 조금 더 이해할 수 있게 됩니다.
create 오퍼레이터는 파라미터로 클로저를 받습니다.
그리고 이 클로저는 AnyObserver라는 제네릭 타입의 파라미터를 받아서 Disposable을 리턴합니다.
여기서 파라미터로 받는 Observer를 이용해서 Observer에게 전달할 이벤트를 정의합니다.
그리고 Disposable을 리턴해주어야 합니다.
파라미터로 받은 observer를 이용해서 방출될 이벤트를 정의합니다.
그리고 Disposables 구조체를 이용해서 Disposable 인스턴스를 생성합니다.
제공되는 메서드는 여러 가지가 있습니다.
Observable이 disposed 될 때 아무것도 하지 않으려면 기본적은 create() 메서드를 이용하면 됩니다.
만약 disposed 될 때 무언인가 하고 싶다면 클로저를 전달하는 메서드를 이용하면 됩니다.
저는 여기서 Disposed 될 때 로그를 출력하도록 만들었습니다.
Memory Leak 예시
create에서 completd, error 이벤트를 방출하지 않거나 dispose 또는 disposed(by:)를 호출하지 않으면 이 Observable은 영원히 메모리에서 삭제되지 않습니다.
참고 자료
728x90'Programming > RxSwift' 카테고리의 다른 글
RxSwift - Trait (0) 2022.03.24 RxSwift - Observable factory (0) 2022.03.21 RxSwift - Subscribe (0) 2022.03.17 RxSwift - Observable (0) 2022.03.05 RxSwift - 개요 (0) 2022.03.03