 iOS/RxSwift

RxSwift - TimeBasedOperators

Younngjun 2022. 11. 7. 17:31
replay

 

반복하는앵무새🦜에 대해 subscribe 하기 전에 "인사말"에서 이벤트를 방출하고 있었다. subscribe 를 늦게 하더라도 replay 에 선언한 buffer 1 만큼의 이전에 방출된 이벤트의 값을 가져올 수 있다.

물론, subscribe 이후 발생하는 이벤트에 대해서는 값을 가져온다.

print("----------replay----------")
let 인사말 = PublishSubject<String>()

let 반복하는앵무새🦜 = 인사말.replay(1)
반복하는앵무새🦜.connect()
인사말.onNext("1. hello")
인사말.onNext("2. hi")
반복하는앵무새🦜
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)
인사말.onNext("3. 안녕하세요")


----------replay----------
2. hi
3. 안녕하세요

 

replayAll

 

replayAll 은 이전에 방출된 이벤트의 값을 모두 가져온다. 

print("----------replayAll----------")
let 닥터스트레인지 = PublishSubject<String>()
let 닥터스트레인지의타임스톤 = 닥터스트레인지.replayAll()
닥터스트레인지의타임스톤.connect()

닥터스트레인지.onNext("도르마무")
닥터스트레인지.onNext("거래를 하러왔다")

닥터스트레인지의타임스톤
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)
    
    
----------replayAll----------
도르마무
거래를 하러왔다

 

buffer

 

buffer 는 최대 count 개의 값을 갖는 Array 형태로 방출한다.

① timeSpan: .second(-) : 2초마다

② count: - 최대 

print("----------buffer----------")
let source = PublishSubject<String>()

var count = 0
let timer = DispatchSource.makeTimerSource()
// 현재 시점부터 2초를 deadline 으로, 매번 1초 마다
timer.schedule(deadline: .now() + 2, repeating: .seconds(1))

// 이벤트가 반복될 때 마다 동작
timer.setEventHandler {
    count += 1
    source.onNext("\(count)")
}
timer.resume()

source
    .buffer(
        timeSpan: .seconds(2),
        // 최대 2개의 값을 갖는 Array 형태로 방출
        count: 2,
        scheduler: MainScheduler.instance
    )
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)
    
    
----------buffer----------
// 2초 내에 이 당시에는 1 밖에 못 받았기 때문에 1이라도 방출
["1"]
["2", "3"]
...

 

window

 

buffer 와 비슷하지만, Array 가 아닌 Observable 들을 방출한다.

print("----------window----------")
let 만들어낼최대Observable수 = 1
let 만들시간 = RxTimeInterval.seconds(2)

let window = PublishSubject<String>()

var windowCount = 0
let windowTimerSource = DispatchSource.makeTimerSource()
windowTimerSource.schedule(deadline: .now() + 2, repeating: .seconds(1))
windowTimerSource.setEventHandler {
    windowCount += 1
    window.onNext("\(windowCount)")
}
windowTimerSource.resume()

window
    .window(
        timeSpan: 만들시간,
        // 하나의 observable 만 계속해서 element 를 방출
        count: 만들어낼최대Observable수,
        scheduler: MainScheduler.instance
    )
    .flatMap { windowObservable -> Observable<(index: Int, element: String)> in
        return windowObservable.enumerated()
    }
    .subscribe(onNext: {
        print("\($0.index)번째 Observable의 요소 \($0.element)")
    })
    .disposed(by: disposeBag)


----------window----------
0번째 Observable의 요소 1
0번째 Observable의 요소 2
0번째 Observable의 요소 3
...

 

delaySubscription

 

정상적으로 이벤트를 방출하지만, subscribe 를 지연시키는 연산자이다.

print("----------delaySubscription----------")
let delaySource = PublishSubject<String>()

var delayCount = 0
let delayTimerSource = DispatchSource.makeTimerSource()
delayTimerSource.schedule(deadline: .now() + 2, repeating: .seconds(1))
delayTimerSource.setEventHandler {
    delayCount += 1
    delaySource.onNext("\(delayCount)")
}
delayTimerSource.resume()

delaySource
    // 5초를 지연시킨다.
    .delaySubscription(.seconds(5), scheduler: MainScheduler.instance)
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)
    
    
----------delaySubscription----------
4
5
...

 

 

delay

 

전체 Sequence 자체를 뒤로 미루는 연산자이다.

print("----------delay----------")
let delaySubject = PublishSubject<Int>()

var delaySubjectCount = 0
let delaySubjectTimerSource = DispatchSource.makeTimerSource()
delaySubjectTimerSource.schedule(deadline: .now(), repeating: .seconds(1))
delaySubjectTimerSource.setEventHandler {
    delaySubjectCount += 1
    delaySubject.onNext(delaySubjectCount)
}
delaySubjectTimerSource.resume()

delaySubject
    .delay(.seconds(3), scheduler: MainScheduler.instance)
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)
    
    
----------delay----------
2
3
4
...

 

interval

 

임의로 만들었던 Timer 를 Rx 로 만들어주는 연산자이다.

아래 코드에서는 3초 간격으로 Int 를 방출한다. (자동으로 타입 추론을 통해 Int 방출)

print("----------interval----------")
Observable<Int>
    .interval(.seconds(3), scheduler: MainScheduler.instance)
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)
    
    
----------interval----------
// 3초 간격으로 Int 를 방출한다.
0
1
2
...

 

timer

 

interval 보다 조금 더 강력한 형태이다. 

① subscribe 하고 첫 번째 값을 방출하는 사이에 마감일을 설정할 수 있다.

print("----------timer----------")
Observable<Int>
    .timer(
        .seconds(5),    //구독 시작 딜레이
        period: .seconds(2),    //간격
        scheduler: MainScheduler.instance
    )
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)
    
    
----------timer----------
// 5초 후 2초 간격으로 이벤트 방출
0
1
2

 

timeout

 

아무런 이벤트가 발생하지 않은 채 정해준 시간을 초과하게 되면 timeout 에러가 발생하도록 한다.

print("----------timeout----------")
let 누르지않으면에러 = UIButton(type: .system)
누르지않으면에러.setTitle("눌러주세요!", for: .normal)
누르지않으면에러.sizeToFit()

PlaygroundPage.current.liveView = 누르지않으면에러

누르지않으면에러.rx.tap
    .do(onNext: {
        print("tap")
    })
    .timeout(.seconds(5), scheduler: MainScheduler.instance)
    .subscribe {
        print($0)
    }
    .disposed(by: disposeBag)