- Published on
๐ Swift - RxSwift
- Authors
- Name
- ์ด์ฐฝ์ค
์ค๋์ ๋ชจ๋๊ฐ ์ฐ์ง๋ง ์ ๋ง ์์ฐ๊ณ ์๋ RxSwift๊ฐ ๋ฌด์์ด๊ณ , ์ด๋ป๊ฒ ์ฐ๋๊ฑด์ง ์์๋ณด๊ฒ ์ต๋๋ค.
์ฐ์ RxSwift๋ Swift๋ง ๊ฐ๊ณ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋๋๋ค. ์๋์ ํ๋ก์ ํธ ๋ช ์ ReactiveX์ด๊ณ ์ด ์ด๋ฆ์ผ๋ก๋ ์ด๋์ ๊ฐ ๋ค์ด๋ดค๋ ๊ฒ ๊ฐ๊ธฐ๋ ํ์ฃ . RxSwift๋ ์ด ReactiveX๋ฅผ Swift์ ์ด์ํ ๋ฒ์ ์ ์ด๋ฆ์ ๋๋ค.
Reactive X
๊ทธ๋ ๋ค๋ฉด ReactiveX๋ ๋ฌด์์ผ๊น์?
๋ณดํต ์ฐ๋ฆฌ๊ฐ ์ง๋ ์ฝ๋๋ ๋๊ธฐ์ (Synchronous) ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ ์ ์ ์ค๋ถํฐ ์๋ ์ค๊น์ง ์์๋๋ก ํ ๋ฒ์ ํ ์ค์ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ์คํ๋์ฃ . ํ์ง๋ง ReactiveX์์๋ ์์ ๋ค์ ์ฐ์ ๋ณ๋ ฌ(parallel)์ ์ผ๋ก ์คํ ํ๊ณ , โobserversโ ๋ผ๋ ๋๋ค๋ก ๋์ค์ ๊ฒฐ๊ณผ๋ฌผ์ ๋ฐ์์ต๋๋ค.
ReactiveX์์ ์์ ์ ์๋ ๊ตฌ์กฐ๋ก ์คํ๋ฉ๋๋ค.
Observable โฌ ๏ธ Subscribe โ๏ธ Observer
Observable์์ ์ด๋ค ํ๋์ด ํฌ์ฐฉ๋๋ฉด Observer๋ ๊ทธ์ ๋ง๋ ๋ฐ์์ ๋ณด๋ด์ค๋๋ค.
Observable
Observable ๋ฐํ
๋น๋๊ธฐ์ฑ(Asynchronous) ๋ชจ๋ธ์ ํ๋ฆ์ ์๋์ ๊ฐ์ต๋๋ค.
- ๋น๋๊ธฐ์ฑ ํธ์ถ์ return ๊ฐ์ ํ์ฉํ์ฌ method๋ฅผ ์ ์ํ๋ค: Observer์ ์ผ๋ถ๋ถ
- ๋น๋๊ธฐ์ฑ ํธ์ถ์ ์ ์ํ๋ค: Observable
- Observer๋ฅผ Observable์ ์ฐ๊ฒฐํ๋ค: Subscribe
- return value์ value๋ฅผ ํ์ฉํ๋ค.
def myOnNext = { it -> do something useful with it };
def myObservable = someObservable(itsParameters);
myObservable.subscribe(myOnNext);
onNext, onCompleted, onError
Subscribe๋ Observer๋ ์ํฉ์ ๋ฐ๋ผ subset์ ๊ฐ์ง๋๋ค.
onNext
Observable์ด ์ด๋ค ์ ๋ณด๋ฅผ ๋ด๋ณด๋ด๋ฉด, onNext
method์ ์ธ์๋ก ๋ฐ์์ต๋๋ค.
onError
์์ํ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ ๋ฐ ์คํจํ๊ฑฐ๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด onError
method๋ฅผ ํธ์ถํฉ๋๋ค. onError method๋ฅผ ํธ์ถํ ์ดํ์๋ onNext
, onCompleted
method๋ฅผ ํธ์ถํ์ง ์์ต๋๋ค. onError
method์ ์ธ์๋ก๋ ๋ฌด์์ด ์๋ฌ๋ฅผ ์ผ์ผ์ผฐ๋์ง ๋ฐ์์ต๋๋ค.
onCompleted
์๋ฌ๊ฐ ๋ฐ์ํ์ง ์์์ ๋, ๋ง์ง๋ง onNext
method๋ฅผ ํธ์ถํ ํ์ ํธ์ถ๋ฉ๋๋ค.
์ ๋ฆฌํด๋ณด๋ฉด, onNext
๋ ์ฌ๋ฌ๋ฒ ๋ฐ์ํ ์๋ ์์ง๋ง onError
์ onCompleted
๋ ์ข๋ ์ซ๋ ํ ๋ฒ๋ง ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค!
def myOnNext = { item -> /* do something userful with item */ };
def myError = { throwable -> /* react sensibly to a failed call */ };
def myComplete = { /* clean up after the final response */ };
def myObservable = someMethod(itsParameters);
myObservable.subscribe(myOnNext, myError, myComplete);
Unsubscribing
Observable
์ด ๋ ์ด์ ๋ชจ๋ํฐ๋ง์ด ํ์ ์์ด์ง ๊ฒฝ์ฐ, subscribe
๋ฅผ ํด์ ํ ์๋ ์์ต๋๋ค.
Observable
์ด unsubscribe ๋๋ฉด, ์๋ก์ด ๋ฐฉ์ถ๊ฐ์ ์์ฑํ๋ ๊ฒ์ ๋ฉ์ถ ์๋ ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์ฃผ์ํ ์ ์, ์ด ๊ณผ์ ์ ์ฝ๊ฐ์ ๋๋ ์ด๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐฉ์ถ๊ฐ์ด ์กฐ๊ธ ๋ ์์ฑ๋ ํ์ ๋ฉ์ถ ์๋ ์์ต๋๋ค.
Hot & Cold Observables
Hot Observable
์์ฑ๋จ๊ณผ ๋์์ ๋ฐฉ์ถ๊ฐ์ด ์์ฑ๋ฉ๋๋ค. Subscribeํ๋ Observer๋ ์ค๊ฐ๊ฐ๋ถํฐ ๊ฐ์ ๋ฐ์๊ฐ๊ฒ ๋ฉ๋๋ค.
Cold Observable
Subscribe ๋๋ฉด, ๊ทธ๋๋ถํฐ ๋ฐฉ์ถ๊ฐ์ด ๋ฐ์ํฉ๋๋ค. ๋๋ฌธ์ Subscribeํ๋ Observer๋ ์์ฑ๋ ๋ชจ๋ ๊ฐ์ ๋ฐ์๊ฐ ์ ์์ต๋๋ค.
Operators
Chaining Operators
๊ฑฐ์ ๋๋ถ๋ถ์ operator๋ค์ Observable ์์์ ์๋ํ๊ณ , Observable์ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์๋ก๊ฐ ์๋ก์๊ฒ ์ฐ๊ฒฐ๋์ด ์ผ์ข ์ ์ฒด์ธ์ ๋ง๋ค ์ ์์ต๋๋ค.
์ด๋ Operator๋ค ๊ฐ์ chain์ ๋ ๋ฆฝ์ ์ผ๋ก ์ํ๋์ง ์์ต๋๋ค. ์ฐ๊ฒฐ๋ ์์์ ๋ฐ๋ผ ์์๋๋ก ํ๋์ฉ ์ํ๋๊ฒ ๋ฉ๋๋ค.
Operators by Category
๊ณต์ ๋ฌธ์๋ฅผ ๋ณด๋ฉด ๊ฐ operator์ ๊ธฐ๋ฅ์ ์นดํ ๊ณ ๋ฆฌํ ํ์ฌ ๋ถ๋ฅํด๋์๋๋ฐ, ์ด๋ฅผ ํ ๋ฒ์ฉ ์ดํด๋ณด๋ฉฐ ์ ๋ฆฌํด๋ณด๊ฒ ์ต๋๋ค!
Creating Observables
create
Observable์ ์์ฑํ ์ ์์ต๋๋ค.
let source: Observable = Observable.create { observer in
for i in 1...5 {
observer.on(.next(i))
}
observer.on(.completed)
return Disposables.create {
print("disposed")
}
}
next(1)
next(2)
next(3)
next(4)
next(5)
completed
disposed
just
๊ฐ๋จํ๊ฒ ์ด๋ค ํ๋์ ๊ฐ์ Observable๋ก ๋ง๋ค๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
let source = Observable.just(1, 2, 3)
let source2 = Observable.just([1,2,3])
1, 2, 3
[1, 2, 3]
from
์ฌ๋ฌ๊ฐ์ ๊ฐ์ด ์๊ณ ๊ฐ๊ฐ์ Observable๋ก ๋ง๋ค๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
let numbers = [1,2,3,4,5]
let source = Observable.from(numbers)
1
2
3
4
5
of
์ฌ๋ฌ๊ฐ์ ๊ฐ์ Observable๋ก ๋ง๋ค๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
from
๊ณผ just
์ ์ค๊ฐ ์ ๋๋ก ์๊ฐํ๋ฉด ๋ฉ๋๋ค.
๋ฐฐ์ด์ ์ฌ์ฉํ์ ๋๋ ๋ฐฐ์ด ๊ทธ๋๋ก ๋ฐฉ์ถํ๊ณ , ์๋๋๋ ๊ฐ๊ฐ์ ๊ฐ์ ํ๋์ฉ ๋ฐฉ์ถํฉ๋๋ค.
let source = Observable.of(1, 2, 3)
let source2 = Observable.of([1, 2, 3])
1
2
3
1, 2, 3
Transforming Observables
map
๊ฐ๊ฐ์ ๊ฐ์ ์ํ๋ ํํ๋ก ๋ณํํ์ฌ Observable๋ก ๋ง๋ค๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
let source = Observable.from([1, 2, 3]).map { $0 * 2 }
2
4
6
flatMap
๊ฐ๊ฐ์ Observable์ด ๋ฐฉ์ถํ ๊ฐ์ ๋ํด ์ง์ ํ ํจ์๋ฅผ ์ ์ฉํฉ๋๋ค. ์ด ๋, ๊ฐ ํจ์๋ ์์ฒด์ ์ผ๋ก ๊ฐ์ ๋ฐฉ์ถํ๋ Observalbe์ ๋ฐํํฉ๋๋ค.
let observableInt = Observable.of(1, 2, 3)
let observableString = Observable.of("A", "B", "C")
observableInt
.flatMap { (x: Int) -> Observable<String> in
return observableString
}
next(A)
next(B)
next(A)
next(C)
next(B)
next(A)
next(C)
next(B)
next(C)
completed
scan
let observable = Observable.of(1, 2, 3).scan(0) { $0 + $1 }
1
3
6
Filtering Observables
filter
๊ฒฐ๊ณผ๋ฅผ ์ํ๋ ์กฐ๊ฑด์ ๋ง๊ฒ ํํฐ๋งํ์ฌ ๋ฐฉ์ถํฉ๋๋ค.
let observable = Observable.from([1, 2, 3]).filter { $0 > 1 }
2
3
first
,last
๊ฒฐ๊ณผ ์ค ๊ฐ์ฅ ์ฒซ๋ฒ์งธ/๋ง์ง๋ง์ ๋ฐฉ์ถํฉ๋๋ค.
let observable = Observable.from([1, 2, 3]).first
Optional(1)
take
,takeLast
๊ฒฐ๊ณผ ์ค ๋ง์ง๋ง/์ฒ์๋ถํฐ n๋ฒ์งธ๊น์ง ๋ฐฉ์ถํ ์ง ์ ํด์ ๋ฐฉ์ถํฉ๋๋ค.
let observable = Observable.from([1, 2, 3]).takeLast(2)
2
3
elementAt
n๋ฒ์งธ ์ธ๋ฑ์ค์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฉ์ถํฉ๋๋ค.
let observable = Observable.from([1, 2, 3]).elementAt(2)
3
Combining Observables
merge
์ฌ๋ฌ Observable์ ๊ฒฐ๊ณผ๋ฅผ ํ๋์ Observable๋ก ํฉํ์ฌ ๋ฐํํฉ๋๋ค. ์ด ๋, ํ๋์ Observable์ด๋ผ๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด, ํฉ์ณ์ง Observable๋ ์ข ๋ฃ๋ฉ๋๋ค.
let observableInt = Observable.of(1, 2, 3)
let observableInt2 = Observable.of(4, 5, 6)
let observableMerge = Observable.of(observableInt, observableInt2).merge()
1
2
4
3
5
6
zip
๊ฐ Observable์ ์์๋๋ก ์ง์ ๋ง์ถ์ด ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฉ์ถํฉ๋๋ค. ์ง์ด ๋ง์ง ์๋ ๊ฐ์ ๋ฒ๋ฆฝ๋๋ค.
let observableInt = Observable.of(1, 2, 3, 4)
let observableString = Observable.of("A", "B", "C")
let observableZip = Observable.zip(observableInt, observableString) {
"\($0)" + $1
}
1A
2B
3C
combineLatest
๊ฐ Observable์ ๋ง์ง๋ง ๊ฐ๋ผ๋ฆฌ์ ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฉ์ถํฉ๋๋ค.
let observableInt = Observable.of(1, 2, 3)
let observableString = Observable.of("A", "B", "C")
let observableCombineLatest = Observable.combineLatest(observableInt, observableString) {
"\($0)" + $1
}
1A
1B
2B
3B
3C