이번 포스팅에는 Observable을 직접 구현하고 구독해보겠습니다!
가장 기본적으로 구현하는 방법은 3가지가 있습니다.
먼저 just를 사용하면 1개의 event만 발행합니다.
of는 여러 개의 인자를 받아서 모두 event로 발행합니다.
from의 경우에는 배열을 받아서 배열 요소들을 발행합니다.
import RxSwift
let observable = Observable.just("하나만")
let observable2 = Observable.of("여", "러", "개")
let observable3 = Observable.from(["배", "열", "에", "서"])
참고로 위 Observable들은 모든 String을 발행하기 때문에 Observable 타입이 됩니다.
위처럼 데이터만 전달하면 자동으로 구현되도록 하지 않고 임의로 직접 구현할 수도 있습니다.
Observable이 발행하는 데이터의 타입을 선언하고 create라는 메소드를 사용합니다. 이 메소드에는 클로저를 하나 전달하는데 그 클로저는 AnyObserver 타입의 인자를 받습니다. 해당 인자를 통해서 onNext로 발행하고 onComplete로 complete하면 됩니다.
그리고 해당 클로저는 반드시 Disposable을 반환해야 합니다.
let observable = Observable<String>.create { observer in
observer.onNext("직")
observer.onNext("접")
observer.onNext("구")
observer.onNext("현")
observer.onCompleted()
return Disposables.create() // Disposable을 반환
}
구독은 기본적으로 subscribe 메소드에 클로저를 전달해서 할 수 있습니다. 해당 클로저는 event를 인자로 받습니다.
출력된 내용을 보면 발행되는 String 데이터가 onNext라는 이벤트에 싸여 출력되는 것을 볼 수 있습니다. 즉 정확히 얘기하면 Observable은 String을 발행하는 것이 아니라 Event 객체를 발행하는 것입니다.
그리고 모든 발행을 마치면 completed라는 이벤트를 발행합니다.
let observable = Observable.from(["배", "열", "에", "서"])
observable.subscribe { event in
print(event)
}
//🖨 출력 결과
next(배)
next(열)
next(에)
next(서)
completed
이벤트 안에 있는 String만 출력하고 싶다면 아래 처럼 event의 element라는 property를 출력하면 됩니다.
다만 이 경우에는 Optional로 싸여있습니다. 또한 complete 이벤트에는 element가 없으니까 nil이 출력되게 됩니다.
observable.subscribe { event in
print(event.element)
}
//🖨 출력 결과
Optional("배")
Optional("열")
Optional("에")
Optional("서")
nil
unwrapping해서 출력한 결과도 한번 보겠습니다.
observable.subscribe { event in
guard let element = event.element else { return }
print(element)
}
//🖨 출력 결과
배
열
에
서
하지만 이런 식으로 unwrapping하는 코드를 매번 넣는 것은 귀찮은 일입니다. 우리가 Observable을 구독할 때는 대부분 Event 객체가 아니라 안에 있는 데이터가 필요한 경우가 대부분 입니다.
따라서 클로저를 바로 전달하지 않고 onNext라는 인자에 전달하면 바로 element에 접근할 수 있습니다.
observable.subscribe(onNext: { element in
print(element)
})
//🖨 출력 결과
배
열
에
서
complete 이벤트가 발생할 때 실행할 클로저를 전달하는 인자도 있습니다. complete 이벤트는 Observable이 발행을 마쳤을 때 1번 발생합니다.
onCompleted에 전달하는 클로저는 인자를 받지 않습니다. (() → Void)
observable.subscribe(
onNext: { element in print(element) },
onCompleted: { print("발행 끝") }
)
//🖨 출력 결과
배
열
에
서
발행 끝
dispose는 구독을 메모리에서 해제하는 작업입니다. Observable이 complete를 발행하고 발행을 마쳤다고 구독 객체가 자동으로 메모리에서 해제되는 것은 아닙니다. dispose()를 통해 직접 메모리에서 해제 해주어야 합니다.
observable
.subscribe(
onNext: { element in print(element) },
onCompleted: { print("발행 끝") })
.dispose()
DisposeBag은 dispose를 전담하는 객체입니다. 구독 객체에 등록해놓으면 dispose를 알아서 해줍니다.
let disposeBag = DisposeBag()
observable
.subscribe(
onNext: { element in print(element) },
onCompleted: { print("발행 끝") })
.disposed(by: disposeBag)
dispose될 때 실행되는 코드를 정의할 수도 있습니다. onCompleted와 마찬가지로 인자가 없는 클로저입니다.
observable
.subscribe(
onNext: { element in print(element) },
onCompleted: { print("발행 끝") },
onDisposed: { print("dispose 됨") })
.disposed(by: disposeBag)
//🖨 출력 결과
배
열
에
서
발행 끝
dispose됨