ReactiveX 기본 개념.
* 이 포스트는 RxSwift 4.3.1, Swift 4.2 버전을 기준으로 작성되었습니다.
ReactiveX(http://reactivex.io/) 에서 소개하는 ReactiveX의 장점은 다음과 같다.
"이벤트를 발생하는 Observable 과 이것을 관찰하는 Observer 를 통해 비동기 이벤트들을 쉽고 안전하게 처리할 수 있는 라이브러리"
iOS 에서는 RxSwift 를 통해 사용가능하고, RxCocoa RxDataSource를 통해 UIComponent 들의 이벤트들도 Rx 로 확장, 사용가능하다.
사용 예를 들어보면 이벤트 타입이 다른 이벤트를 같이 묶어서 처리 하는 형태가 쉽게 구현이 가능하다.
request 를 두개 요청해야 하고, 그 응답을 같이 받아 처리해야만 하는 경우에도, observable 합성 동작을 통해, 두가지의 응답을 하나로 묶을 수 있다.
연결관계가 없는 A 모듈과 B 모듈사이에 이벤트를 전달해야 할때 어떻게 할 것인가?
일반적으로 사용되는 것은 NotificationCenter 를 통한 방법이 있고, 전역 변수를 통해 자원을 공유하는 방법이있다. Rx 에서는 Subject 를 통해 notification center 처럼 구현이 가능하며 문법도 간결하다.
RxSwift 를 프로젝트 파일에 추가하고 ViewController 에서 간단한 테스트를 통해 Observable 과 Subscribe 에 대해 이해해 보자.
동물의 행동을 관찰하는 프로그램을 만들어 보자.
1. 토끼는 3초에 한번 모습을 보인다.
2. 나는 관찰자로써 토끼가 나올때 토끼등장 이라고 말한다
3초에 한번 토끼가 나타나는 이벤트(Observable) 을 만들어보자
import UIKit
import RxSwift
class Zootopia {
struct Rabbit{
let comment = "토끼 등장!"
}
let disposeBag = DisposeBag()
let timer = Observable<Int>.interval(3.0, scheduler: MainScheduler.instance)
init() {
timer.map{ _ in Rabbit() }.subscribe(onNext: { rabbit in
print(rabbit.comment)
}).disposed(by: disposeBag)
}
}
Zootopia 클래스 설명
Observable<Int>.interval(3.0, scheduler: MainScheduler.instance)
interval 메서드는 period (sec) 과 scheduler 를 인자로 받아서 해당 시간값 Int 이벤트(emit)를 발생하는 Observable 이다.
예제에서는 0...1...2...3 이런식으로 시간간격 3초마다 증가된 Int 이벤트(emit)를 발생한다.
Reactive.io document 링크
http://reactivex.io/documentation/operators/interval.html
timer.map{ _ in Rabbit() }.subscribe(onNext : { rabbit in
print(rabbit.comment)
}).disposed(by: disposeBag)
Observable 이벤트를 Rabbit 객체로 매핑해준다. 이제 3초마다 새로운 rabbit struct 가 이벤트로 전달된다. subscribe는 발생한 이벤트(emit) 를 구독하는 syntax 이다.
let disposeBag = DisposeBag()
이 구문은 ARC 의 개념을 생각하고 이해하면 쉬운데, dispose()를 명시적으로 호출하면 해당 Observer는 종료된다. DisposeBag 을 생성하고 disposed(by:) 를 통해 설정해주면, disposebag 변수를 초기화 하거나 deinit 되면 Observer는 종료된다.
RxSwift 내 DisposeBag.swift 내용.
deinit {
dispose()
}
3초마다 "토끼등장!" 이 print 된다.
1.(Cold) Observable 은 이벤트를 생성하지만 observer 가 없다면 이벤트를 발생하지 않는다.
( Hot Observable은 observer와 관계없이 이벤트를 발생시킨다. )
2. 하나의 Observable 에 여러 observer를 등록(subscribe) 할 수 있다.
3. observer 는 dispose 가 되기 전까지 Observable 의 이벤트를 구독한다.
func myInterval(_ interval: TimeInterval) -> Observable<Int> {
return Observable<Int>.create { observer in
print("Subscribed")
let timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())
timer.schedule(deadline: DispatchTime.now() + interval, repeating: interval)
let cancel = Disposables.create {
print("Disposed")
timer.cancel()
}
var next = 0
timer.setEventHandler {
if cancel.isDisposed {
return
}
observer.on(.next(next))
next += 1
}
timer.resume()
return cancel
}
}
DispatchSource 는 iOS 10 이상, XCode 8 이상, Swift 에서 사용가능.
Observable 을 이해하기 쉬운 예제라서 첨부.