본문 바로가기

iOS

[iOS] [Swift] RxSwift Observable & Observer, Disposable

Observable & Observer, Disposable

 

이번 시간에는 RxSwift의 기초를 보다 자세히 알아보도록 하겠습니다.

 

1. Observable & Observer


Observable 은 이름에서 알 수 있듯, 관찰가능한 상태를 유지하며 Event를 전달합니다.

 

해당 Event를 Observer 관찰자에게 전달하고 이벤트를 전달받으면 이를 Observer 에서 처리합니다.

 

이러한 행위를 Rx에서는 구독(Subscribe) 한다고 표현하기에 Observer 를 "구독자" 라고도 부릅니다.

 

요즘 매우 많이 사용하는 Youtube 서비스에 빗대어 표현하자면 크리에이터가 Observable 역할을 하여 영상(이벤트)를 발행하고 해당 크리에이터를 구독하던 Observer 구독자가 영상을 시청하는 흐름과 매우 유사합니다.

 

Observable 은 3가지 종류의 이벤트를 발행할 수 있습니다.

 

Observable 에서 새로운 이벤트가 발생하면 이를 next 이벤트로 Observer 에게 전달합니다.

 

이러한 행위를 Rx에서는 방출(Emit) 이라고 표현합니다.

 

만일 Observable 에서 에러가 발생한다면 error 이벤트를 전달하게 됩니다.

 

반면, Observable 이 정상적으로 종료된다면 completed 이벤트를 전달하게 됩니다.

 

error, completed 이벤트는 Observable의 생명주기 중 가장 마지막에 전달되어 집니다.

 

따라서, 이후에는 Observable이 종료되고 모든 리소스가 정리되어집니다.

 

Observable이 방출하는 이벤트를 Observer가 받아내서 처리하기 위해서는 구독 행위가 필요하다고 앞서 언급하였습니다.

구독을 하기 위해서는 subscribe 메소드를 호출합니다.

 

subscribe 메소드를 통해 Observer와 Observable을 연결하여 이벤트를 전달하고 처리할 수 있도록 합니다.

 

간단히 예시를 살펴보도록 하겠습니다.

print("Observable1 생성")
let observable1 = Observable<Int>.from([1, 2, 3, 4, 5])

print("Observer1이 Observable1을 구독합니다.")
let observer1 = observable1.subscribe({ (event) in
    print(event)
})

/*
    Observable1 생성
    Observer1이 Observable1을 구독합니다.
    next(1)
    next(2)
    next(3)
    next(4)
    next(5)
    completed
*/

위 코드를 살펴보면 알 수 있듯, Observable에서 방출하는 이벤트를 하나하나 순차적으로 전달하며 이를 Observer가 받아서 출력합니다.

 

subscribe 메소드를 통해 Observable과 Observer를 연결하여 구독 행위를 진행합니다.

 

2. Disposable

이번에는 Disposable에 대하여 알아보겠습니다.

 

subscribe 메소드 중 한 가지 원형을 살펴보겠습니다.

 

image

 

앞서 Observable은 3 가지 유형의 이벤트 next, error, completed 를 방출할 수 있다고 하였습니다.

 

위 메소드는 이벤트 유형에 따라 분기 처리가 가능하며 기본적으로 (() -> Void)? 으로 옵셔널 타입의 클로저를 채택하기 때문에 반드시 모든 클로저를 작성할 필요는 없습니다.

 

제일 하단에 보면 onDisposed 라는 옵셔널 타입의 클로저 인자를 확인하실 수 있습니다.

 

onDisposed는 Observable과 관련된 모든 리소스가 제거된 이후에 호출되는 클로저입니다.

 

따라서, 해당 Observable이 메모리에서 해제되는 순간 실행시키고 싶은 내용을 기입합니다.

 

위 메소드를 아래와 같이 작성 해보겠습니다.

print("Observable1 생성")
let observable1 = Observable<Int>.from([1, 2, 3, 4, 5])

print("Observer1이 Observable1을 구독합니다.")

let observer1 = observable1.subscribe { event in
    print("onNext 호출")
} onError: { err in
    print("onError 호출")
} onCompleted: {
    print("onCompleted 호출")
} onDisposed: {
    print("onDisposed 호출")
}

/*
    Observable1 생성
    Observer1이 Observable1을 구독합니다.
    onNext 호출
    onNext 호출
    onNext 호출
    onNext 호출
    onNext 호출
    onCompleted 호출
    onDisposed 호출
*/

코드와 결과값을 살펴보면 onNext -> onCompleted -> onDisposed 순서로 클로저가 작동한 것을 확인하실 수 있습니다.

 

앞서 completed 이벤트는 Observable의 생명주기 중 마지막에 호출된다고 하였습니다.

 

error 혹은 completed 이벤트로 Observable이 종료되었을 경우에는 관련 리소스가 메모리에서 정상적으로 해제됩니다.

 

메모리에서 해당 Observable이 해제되는 행위를 RxSwift에서는 Dispose 라고 표현합니다.

 

따라서, onNext 로 모든 next 이벤트를 처리한 이후 정상적으로 종료됨과 동시에 onCompleted 가 호출되고 해당 Observable이 메모리에서 해제되면서 onDisposed가 호출되어집니다.

 

이는 메모리 관리와 매우 밀접한 내용이므로 유심히 봐야 할 필요가 있습니다.

 

Observable이 error 혹은 completed 이벤트를 호출하고 종료되면 따로 리소스 관리를 해 줄 필요 없이 정상적으로 메모리가 해제되지만, RxSwift의 공식 가이드라인을 살펴보면 이 경우에도 manual하게 리소스 정리를 하는 것을 권고하고 있습니다.

 

이 때 사용하는 것이 Disposable 입니다.

 

앞서 사용했던 메소드의 선언형을 다시 살펴보겠습니다.

 

image

onNext, onError, onCompleted, onDisposed 라는 옵셔널 타입 클로저를 인자로 받고 Disposable 타입을 반환합니다.

 

우리는 이를 observer1 이라는 변수에 받았습니다.

 

image

예상대로 observer1 의 타입이 Disposable 타입입니다.

 

RxSwift 공식 가이드의 권고에 따라 Disposable 타입을 모두 모아서 한번에 해제할 수 있는 DisposableBag을 이용하는 에제를 보겠습니다.

 

print("DisposableBag 생성")
let disposeBag = DisposeBag()

Observable<Int>.from([1, 2, 3, 4, 5])
    .subscribe {
        print($0)
    }
    .disposed(by: disposeBag)

/*
    DisposableBag 생성
    next(1)
    next(2)
    next(3)
    next(4)
    next(5)
    completed
*/

위와 같이 Observable을 생성함과 동시에 구독하고 리턴값을 받지않고 바로 dispose 시키면 더욱 편리하게 RxSwift를 사용할 수 있습니다.

 

참고로, DisposableBag에 담긴 DisposableDisposableBag이 해제되는 시점에 모두 함께 해제되어집니다.

'iOS' 카테고리의 다른 글

[iOS] [Swift] RxSwift Operators Example  (0) 2020.11.20
[iOS] [Swift] RxSwift Subject & Relay & Driver  (1) 2020.11.19
[iOS] Blur Effect in iOS  (0) 2020.11.11
LLVM (Low-Level-Virtual-Machine)  (0) 2020.10.31
[iOS] [Swift] Moya - Networking Library  (0) 2020.10.21