RxSwift를 21일간 공부하는 루틴
"Rx를 기깔나게 쓰는 신입개발자 도전" 시작 🚀
RxSwift에서 제공하는 operator중 먼저, 생성에 관련된 operator를 정리해보겠다.
각각의 create operator 의 특징을 고려해 아래와 같이 언제 사용해야 적절할지에 대해 고민해보았다.
그리고 그 고민의 결과를 플로우차트로 나타내보았다.
이제 하나하나씩 자세히 정리해보도록하겠다.
앞선 정리글에서 여러번 create
연산자를 사용한 적이 있다.
create
를 사용한다면, observable을 직접 구현할 수 있다.
Observable<String>.create { observer in
observer.onNext("🏋🏻♀️")
observer.onCompleted()
//observer.onError(Err.error)
return Disposables.create()
}.subscribe(
onNext: { print("Next",$0) },
onError: { print("Error",$0) },
onCompleted: { print("Completed") },
onDisposed: { print("Disposed") }
).disposed(by: disposeBag)
물론 create
를 사용해 이벤트를 방출해 줄 수 있지만, 구현 해야하는 상황에 맞는 연산자를 잘 활용한다면 더욱 효율적이라고 생각한다.
create
이후에 정리할 연산자는 파라미터로 전달된 요소를 방출한다.
range
는 공차가 1인 등차수열이다.
range
는 방출시 조건을 파라미터로 받지않는다.
range
의 definition을 보면 다음과 같다.
파라미터로 start, count, scheduler를 받는데 이때 scheduler는 초기값이 지정되어있어서, start와 count값을 필수로 넘겨줘야한다.
//MARK: Range
Observable.range(start: 0, count: 5)
.subscribe { print("range : \($0)")}
.disposed(by: disposeBag)
다음과 같이 생성해 줄 수 있다.
start는 시작값이고, count는 몇개를 방출할 지에 대한 파라미터이다.
따라서 0부터 1씩 증가하는 시퀀스를 방출하는데 이때 5개를 방출 한다.
output은 다음과 같다.
range : next(0)
range : next(1)
range : next(2)
range : next(3)
range : next(4)
range : completed
그렇다면, 감소하는 시퀀스를 만들고 싶거나 공차가 1이 아닌 시퀀스를 만들고 싶을 때는 어떻게 해야할까에 대한 고민을 해결해 주는 연산자가 generate
이다.
generate
의 경우, 파라미터로 받는 condition을 통해 조건을 추가해 줄 수 있고, iterate를 통해 step (공차)을 정해 줄 수 있다.
만약, 5가 시작값이고 2씩 감소하는 시퀀스인데, 0보다 클때 까지만 방출 하고 싶다면, 다음과 같이 generate
를 활용해 구현할 수 있다.
//MARK: generate
Observable.generate(initialState: 5, condition: { $0 >= 0 }, iterate: { $0 - 2 })
.subscribe { print("generate : \($0)")}
.disposed(by: disposeBag)
initialState 를 통해 5 부터 시작함을 알 수 있다.
그다음 파라미터인 condition 을 보면 bool을 반환하고 true 일때만 next 이벤트를 방출해준다. 마지막 파라미터인 iterate는 step (우리가 알고있는 등차수열의 공차와 비슷한 역할)을 정해줄 수 있다.
위 코드를 실행 했을 때 다음과 같은 output을 얻게된다.
generate : next(5)
generate : next(3)
generate : next(1)
generate : completed
그렇다면 만약 동일한 요소만을 방출하고 싶을때는 어떤 연산자를 쓸 수 있을까?
repeat
를 사용할 수 있다.
repeat
의 경우 플로우 차트를 다시 보면, 조건을 추가할 것인가에 yes 에 해당된다. 물론 파라미터로 조건을 받지는 않지만 repeat
를 사용하면 무한루프에 빠질 수 있다. 따라서 take
연산자를 활용해 몇개를 방출할지, 방출되는 요소의 수를 정해 줄 수 있다.
//MARK: Repeat
Observable.repeatElement(0)
.take(3)
.subscribe{ print("repeat : \($0)")}
.disposed(by: disposeBag)
이 코드를 실행 시킨다면, next(0) 이벤트를 3번 방출하고 ,completed를 전달하게 된다.
이번에 어떠한 step이 있는 시퀀스를 만드는 경우가 아닌, 조건에 따라 Observable을 생성하고 싶을 때 쓸 수 있는 deferred
에 대해 정리해보겠다.
deferred
는 generate
처럼 파라미터로 조건을 받지는 않는다.
하지만 deferred의 생성시점을 고려하면 조건과 함께 사용하는게 더 적절하다고 생각하여, 플로우 차트에 표현하였다.
deferred
의 정의를 보면 다음과 같다.
다른 operator와의 차이점은 구독하기 전까지 생성하지 않는다.
따라서 필요할 때 구독을 사용해 원하는 시퀀스로 생성할 수 있다.
즉 새로운 관찰자가 구독을 할때, 지정된 시퀀스를 리턴하게 된다.
let factory : Observable<Int> = Observable.deferred {
flag.toggle()
cnt += 1
if flag {
return Observable.from([1,3,5])
} else {
return Observable.from([2,4,6])
}
}
factory.subscribe { print("deferred toggle \(cnt) : \($0)") }
.disposed(by: disposeBag)
factory.subscribe { print("deferred toggle \(cnt) : \($0)") }
.disposed(by: disposeBag)
flag 값은 bool 타입으로 초기값은 false 로 지정해 두었다.
toggle 이 된다면, true가 되고, Observable.from([1,3,5])
가 실행이 될 것이다.
이때, deferred의 특징상 toggle이 되기 위해서는 새로운 구독자를 추가해야한다.
만약 또다른 새로운 구독자를 추가한다면 다시 toggle이 되어, Observable.from([2,4,6])
가 return 이 된다.
output 에서 확인 가능하다.
deferred toggle 1 : next(1)
deferred toggle 1 : next(3)
deferred toggle 1 : next(5)
deferred toggle 1 : completed
deferred toggle 2 : next(2)
deferred toggle 2 : next(4)
deferred toggle 2 : next(6)
deferred toggle 2 : completed
이 처럼 , flag를 통해 조건을 추가하여 생성을 다르게 해 줄 수 있다.
전체코드는 깃허브에서 확인 가능하다.
다음에는 filter Operator에 대해 정리해보겠다.