본문 바로가기
iOS/RxSwift

[RxSwift] Observable.create & Disposable.create

by 0inn 2022. 11. 22.

어제 노티 관련 포스팅 중에 Disposable.create에 대한 의문이 생겼었습니다.

왜 저걸 해주는 거지 ?

그래서 . . 오늘 Rx 코드 뜯어보면서 알아보려고 합니다 !

혼자 공부한 것이므로 틀린 내용이 있을 수 있습니다 . .

 

자 그럼 Disposable.create를 알아보기 전에 . .

그 앞에 Observable.create부터 살펴봐야겠죠 ?

왜냐면 ~ 저번 Noti + Rx에서 Observable.create으로 먼저 Noti를 생성한 후에 Disposable.create로 remove 해주고 있으니까 . .

 

전에 RxSwift - Observable 포스팅에서 create(:)에 대해 정리했었는데요.

"create은 escaping 클로저로 escaping에서는 AnyObserver를 취한 뒤 Disposable을 리턴합니다." 라고 설명하고 있습니다.

Observable.create()

public static func create(_ subscribe: @escaping (AnyObserver<Element>) -> Disposable) -> Observable<Element> {
    AnonymousObservable(subscribe)
}

create은 subscribe 파라미터를 가지고 있네요 !

이 파라미터는 AnyObserver를 가져와 Disposable로 변환하는 escaping 클로저입니다.

그리고 결국 create는 Observable을 리턴하네요 !

 

[ 간단 설명 ]

AnyObserver는 구독자에게 방출될 observable sequence에 값을 추가하기 편한 제네릭 타입입니다.

Generic은 타입에 의존하지 않는 범용 코드를 작성하기 위해 사용합니다.

 

이제 함수 body 부분을 볼게요.

Observable.create()을 호출하면 AnnoymousObservable을 만들게 됩니다.

AnnoymousObservable

final private class AnonymousObservable<Element>: Producer<Element> {
    typealias SubscribeHandler = (AnyObserver<Element>) -> Disposable

    let subscribeHandler: SubscribeHandler

    init(_ subscribeHandler: @escaping SubscribeHandler) {
        self.subscribeHandler = subscribeHandler
    }
    
    // override func ~
}

코드를 살펴보면 넘겨준 subscribe를 통해 Disposable이 리턴되는 것을 알 수 있습니다.

 

정리해보자면 Observable.create()을 호출하면 Disposable을 리턴합니다.

리턴 타입을 명시하지 않으면 에러가 발생하겠죠 !

그렇기 때문에 Disposable.create()으로 Disposable을 생성해 리턴해줘야 합니다.

 

그렇다면 다시 돌아와서 Disposable.create()에 대해 알아볼게요.

Dispoable.create()

Disposable.create3가지 경우가 존재하는데요.

 

1. NoDisposable

extension Disposables {
    /**
     Creates a disposable that does nothing on disposal.
     */
    static public func create() -> Disposable { NopDisposable.noOp }
}

NoDisposable.noOp를 반환하며 dispose가 호출되어도 아무것도 하지 않습니다. 

 

2. CompositeDisposable

extension Disposables {

    /// Creates a disposable with the given disposables.
    public static func create(_ disposable1: Disposable, _ disposable2: Disposable, _ disposable3: Disposable) -> Cancelable {
        CompositeDisposable(disposable1, disposable2, disposable3)
    }
    
    /// Creates a disposable with the given disposables.
    public static func create(_ disposable1: Disposable, _ disposable2: Disposable, _ disposable3: Disposable, _ disposables: Disposable ...) -> Cancelable {
        var disposables = disposables
        disposables.append(disposable1)
        disposables.append(disposable2)
        disposables.append(disposable3)
        return CompositeDisposable(disposables: disposables)
    }
    
    /// Creates a disposable with the given disposables.
    public static func create(_ disposables: [Disposable]) -> Cancelable {
        switch disposables.count {
        case 2:
            return Disposables.create(disposables[0], disposables[1])
        default:
            return CompositeDisposable(disposables: disposables)
        }
    }
}

파라미터로 받은 disposable들로 disposable을 만듭니다.

 

3. AnnoymousDisposable ✓ → Notification에서 return 타입으로 사용한 애 !!!

extension Disposables {

    /// Constructs a new disposable with the given action used for disposal.
    ///
    /// - parameter dispose: Disposal action which will be run upon calling `dispose`.
    public static func create(with dispose: @escaping () -> Void) -> Cancelable {
        AnonymousDisposable(disposeAction: dispose)
    }

}

파라미터로 @escaping 클로저를 받아 AnnoymousDisposable을 만들어 Calcelable로 리턴합니다.

 

Cancelable

/// Represents disposable resource with state tracking.
public protocol Cancelable : Disposable {
    /// Was resource disposed.
    var isDisposed: Bool { get }
}

Calcelable이란 Disposable을 채택하는 프로토콜로 현재 Disposable이 dispose 되었는지 확인하는 프로퍼티를 제공합니다.

 

뭐 쨋든 클로저를 전달하여 dispose가 호출되면 해당 클로저를 호출하는 방식이 됩니다.

 

그럼 궁금했던 . . Notification + Rx 에서 return Disposable.create()를 다시 볼게요

return Disposables.create {
    self.base.removeObserver(nsObserver)
}

사용하지 않는 observer를 제거하기 위해 removeObserver를 해줘야 했습니다.

그렇기 때문에 저희는 !! create으로 생성한 observer(noti)가 더 이상 구독하지 않는 상태가 되어 dispose를 호출하면 이 removeObserver가 실행되게 해줘야 합니다.

그래서 클로저로 removeObserver를 넘겨줘서 dispose되면 사용하지 않는 observer(noti)를 제거할 수 있게 되는 것이죠 !

 

어쩌다보니 Notification하다가 여기까지 넘어왔는데요 . .

RxSwift 기초를 더 단단히 다져야겠다는 생각이 들었습니다 . . 화이팅


참고

https://www.kodeco.com/books/rxswift-reactive-programming-with-swift/v4.0/chapters/2-observables

https://jeonyeohun.tistory.com/365