오늘은 RxSwift 중에서 Observable
, Traits
, 그리고 자주 사용되는 Operation
연산자들을 배웠다.
ReactiveX(Rx)
는 Microsoft 사에서 만든 라이브러리로, 비동기 프로그래밍
과 옵저버 패턴
을 쉽게 구현할 수 있도록 돕는 라이브러리이다. 데이터의 변화에 반응하는 프로그래밍을 하게되어 반응형 프로그래밍
이라고도 하며,
ReactiveX
를 적용한 Swift 라이브러리를 RxSwift
라고 한다.
Observable.just
let observable = Observable.just("Max")
observable.subscribe(onNext: { data in
print("onNext: \(data)")
}).disposed(by: disposeBag)
Observable.of
let observable = Observable.of("red", "blue", "yellow")
observable.subscribe(onNext: { data in
print("onNext: \(data)")
}).disposed(by: disposeBag
Observable.from
let observable = Observable.from([1, 2, 3, 4, 5])
observable.subscribe(onNext: { data in
print("onNext: \(data)")
}).disposed(by: disposeBag)
Observable.interval
let scheduler = SerialDispatchQueueScheduler(qos: .default)
let observable = Observable<Int>.interval(.seconds(1), scheduler: scheduler)
.take(5) // 5번만 방출
observable.subscribe(onNext: { data in
print("onNext: \(data)")
}).disposed(by: disposeBag)
let input = readLine() // input이 들어오기 전까지 Xcode Command Line Tools가 종료되지 않도록 하기위해 선언
Trait
은 Observable 중에서도 특별한 상황에 맞게 제공되는 Observable 을 말한다.
Single
let single = Single<Int>.create { observer in
observer(.success(100))
return Disposables.create()
}
let single2 = Single<Int>.create { observer in
observer(.failure(MyError()))
return Disposables.create()
}
let single3 = Single<Int>.create { observer in
observer(.success(100))
observer(.success(200))
return Disposables.create()
}
single3.subscribe(onSuccess: {data in
print("onSuccess: \(data)")
}, onFailure: { error in
print("onFailure: \(error)")
}).disposed(by: disposeBag)
Maybe
let maybe1 = Maybe<Int>.create { observer in
observer(.success(100))
return Disposables.create()
}
let maybe2 = Maybe<Int>.create { observer in
observer(.error(MyError()))
return Disposables.create()
}
let maybe3 = Maybe<Int>.create { observer in
observer(.success(100))
observer(.success(200))
return Disposables.create()
}
let maybe4 = Maybe<Int>.create { observer in
observer(.completed)
return Disposables.create()
}
maybe4.subscribe(onSuccess: { data in
print("onSuccess: \(data)")
}, onError: { error in
print("onError: \(error)")
}, onCompleted: {
print("onCompleted")
}).disposed(by: disposeBag)
Completable
let completable1 = Completable.create { observer in
observer(.completed)
return Disposables.create()
}
let completable2 = Completable.create { observer in
observer(.error(MyError()))
return Disposables.create()
}
completable2.subscribe(onCompleted: {
print("onCompleted")
}, onError: { error in
print("onError: \(error)")
}).disposed(by: disposeBag)
Rx에서 제공하는 연산자로 Observable을 변환하거나 결합하며, 데이터 흐름을 제어하는 데 도움을 준다.
map
let observable = Observable<Int>.create { observer in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
return Disposables.create()
}
observable
.map { $0 * 10 }
.subscribe(onNext: {
print("onNext: \($0)")
}).disposed(by: disposeBag)
zip
let observableA = Observable<Int>.create { observer in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onNext(4)
return Disposables.create()
}
let observableB = Observable<String>.create { observer in
observer.onNext("A")
observer.onNext("B")
observer.onNext("C")
return Disposables.create()
}
Observable.zip(
observableA,
observableB
)
.subscribe(onNext: { data in // data는 (int, String)의 튜플
print("onNext: \(data.0), \(data.1)")
}).disposed(by: disposeBag)
merge
let observableA = Observable<Int>.interval(.seconds(2), scheduler: SerialDispatchQueueScheduler(qos: .default))
.take(3)
.map { "A -> \($0)번째 방출" }
let observableB = Observable<Int>.interval(.seconds(5), scheduler: SerialDispatchQueueScheduler(qos: .default))
.take(3)
.map { "B -> \($0)번째 방출" }
Observable.merge(
observableA,
observableB
)
.subscribe(onNext: { value in
print("onNext: \(value)")
}).disposed(by: disposeBag)
let input = readLine()
flatMap
let observable = Observable<Int>.interval(.seconds(2), scheduler: SerialDispatchQueueScheduler(qos: .default))
.take(5)
let fruitDictonary = [
0: "사과",
1: "바나나",
2: "오렌지",
3: "멜론"
]
func getFruitObservable(_ number: Int) -> Observable<String> {
return Observable.create { observer in
guard let fruit = fruitDictonary[number] else {
observer.onError(MyError())
return Disposables.create()
}
observer.onNext(fruit)
return Disposables.create()
}
}
observable
.flatMap { data in
return getFruitObservable(data)
}.subscribe(onNext: { data in
print("onNext: \(data)")
}, onError: { error in
print("onError: \(error)")
}).disposed(by: disposeBag)
let input = readLine()
강의에서 다룬 Operation은 위와 같고, 추가로 concat
, combineLatest
, withLastestFrom
, share
, filter
등도 공부해보기로 하였다.
combineLatest
let observableA = Observable.of(1, 2, 3)
let observableB = Observable.of("A", "B", "C")
Observable.combineLatest(observableA, observableB) { a, b in
return "\(a) and \(b)"
}
.subscribe(onNext: { data in
print("onNext: \(data)")
}).disposed(by: disposeBag)
filter
true
를 반환하는 경우에만 값을 방출한다.let observable = Observable.of(1, 2, 3, 4, 5)
observable.filter { $0 % 2 == 0 }
.subscribe(onNext: { data in
print("onNext: \(data)")
}).disposed(by: disposeBag)
concat
let observableA = Observable.of(1, 2, 3)
let observableB = Observable.of(4, 5, 6)
Observable.concat(observableA, observableB)
.subscribe(onNext: { data in
print("onNext: \(data)")
}).disposed(by: disposeBag)
withLatestFrom
let trigger = PublishSubject<Void>()
let data = BehaviorSubject(value: "Initial")
trigger.withLatestFrom(data)
.subscribe(onNext: { value in
print("onNext: \(value)")
}).disposed(by: disposeBag)
data.onNext("Updated")
trigger.onNext(())
share
let observable = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
.take(5)
.share()
observable.subscribe(onNext: { data in
print("Subscriber 1: \(data)")
}).disposed(by: disposeBag)
observable.subscribe(onNext: { data in
print("Subscriber 2: \(data)")
}).disposed(by: disposeBag)