RxSwift - Buffer & Window
안녕하세요. 그린입니다🟢
이번 포스팅에서는 RxSwift의 Buffer와 Window에 대해 학습해보겠습니다🏃🏻
이전 포스팅에서 Debounce와 Throttle에 대해 학습해볼때 잠깐 Buffer와 Window를 봤었어요!
그런데 타이머를 두는것도 그렇고 비슷한것 같은데 어떤 차이가 있는지 궁금해졌습니다.
이에 요 포스팅에서 두개를 알아보려합니다🧐
Buffer
Buffer란?
Buffer는 옵저버블에서 방출하는 이벤트를 번들로 한번에 묶어서 묶음으로 방출하게 해줍니다.
아래 그림과 같은 플로우입니다.
그림을 보면 빨간 이벤트가 발생하고 어느정도의 TimeSpan이후 빨/노/초 이벤트에 대해 묶어 방출시켜줍니다.
Buffer의 선언
import RxSwift
public func buffer(
timeSpan: RxTimeInterval,
count: Int,
scheduler: SchedulerType
) -> Observable<[Element]> {
BufferTimeCount(
source: self.asObservable(),
timeSpan: timeSpan,
count: count,
scheduler: scheduler
)
}
파라미터 시그니쳐를 파악해보겠습니다.
- timeSpan
어느정도의 일정시간의 간격 타임을 줄것인지에 대해 timeSpan을 받습니다.
해당 timeSpan이후 묶여진 이벤트 묶음이 방출됩니다.
즉 이 timeSpan이란것은 항목을 수집하는 시간을 뜻합니다.
- count
버퍼 번들에 최대 몇개까지의 요소를 담을지를 결정해줍니다.
count로 정해준 요소의 갯수만큼 수집이 되지 않더라도 timeSpan이 끝나면 반환됩니다.
- scheduler
해당 연산자가 실행될 쓰레드를 결정해줍니다.
정리해보면 위의 3가지 파라미터를 받아 옵션을 정하고 옵저버블의 어레이를 반환해주는 기능을 해줍니다.
Buffer의 사용
import RxSwift
Observable<Int>
.interval(
.seconds(1),
scheduler: MainScheduler.instance
)
.buffer(
timeSpan: .seconds(2),
count: 2,
scheduler: MainScheduler.instance
)
.take(3)
.subscribe {
print($0)
}
.disposed(by: disposeBag)
// OutPut
[0, 1]
[2, 3]
[4, 5]
제가 좀 가로로 늘어지는걸 별로 안좋아해 세로로 좀 보기쉽게 컨벤션을 맞췄습니다.
우선 위와 같이 1초마다 옵저버블이 방출되게 해주었습니다.
그리고 버퍼를 통해 2초동안 최대 2개의 항목을 수집할 수 있도록 구현해줍니다.
또한 take로 3개까지만 가져오도록 해줍니다.
이렇게 돌려보면 아웃풋이 2개의 항목씩 배열로 묶여 방출되는걸 볼 수 있습니다.
만약 여기서 아래와 같이 timeSpan을 여유롭게 변경해보도록 하죠!
import RxSwift
Observable<Int>
.interval(
.seconds(1),
scheduler: MainScheduler.instance
)
.buffer(
timeSpan: .seconds(10),
count: 2,
scheduler: MainScheduler.instance
)
.take(3)
.subscribe {
print($0)
}
.disposed(by: disposeBag)
// OutPut
[0, 1]
[2, 3]
[4, 5]
timeSpan을 10초로 변경해도 동일한 아웃풋입니다.
10초동안 수집할뿐이지 최대 수집할 수 있는 항목은 2개이기 때문이니까요.
그럼 마지막으로 timeSpan을 적게 count를 많이 해보겠습니다.
import RxSwift
Observable<Int>
.interval(
.seconds(1),
scheduler: MainScheduler.instance
)
.buffer(
timeSpan: .seconds(3),
count: 5,
scheduler: MainScheduler.instance
)
.take(3)
.subscribe {
print($0)
}
.disposed(by: disposeBag)
// OutPut
[0, 1, 2]
[3, 4, 5, 6]
[7, 8, 9]
자 잘보면 3초의 timeSpan을 주었으니 3초동안 수집합니다.
최대 수집 항목의 갯수는 5개구요.
그래서 1초의 1개씩 방출되니 3개씩 들어오는걸 확인할 수 있습니다.
그러나 두번째 아웃풋을 보면 4개의 항목이 수집되었죠?
간혹 이렇게 시간 오차로 인해 발생하는 경우도 있습니다.
그러나 어떠한 오차더라도 count로 지정한 최대값의 수집을 넘을 순 없습니다😃
이렇게 Buffer에 대해 알아보았습니다.
그러면 이어서 Window는 Buffer와 어떤 공통점과 차이점이 있는지 알아보도록 하죠🙋🏻
Window
Window란?
Buffer와 달리 옵저버블의 항목을 묶음이 아닌 하나씩 방출해줍니다.
좀 쉽게 이해해보자면 어떠한 가림막이 있다고 생각해보죠.
이 가림막이 timeSpan동안은 닫혀있어요.
그리고 timeSpan이 지나면 가림막이 열립니다.
그러면 가림막을 통과하지 못하고 있던 옵저버블들이 방출되게 됩니다.
Buffer는 이러한 가림막 대신 어떠한 번들에 묶어 같이 방출했다치면
Window는 묶지 않고 가림막 뒤에 있다 짠하고 가림막이 치워지면 진행되는점입니다.
플로우 그림을 보면 좀 더 빠른 이해를 할 수 있습니다.
여기서 3개씩 가림막이 치워지는것은 Buffer와 마찬가지로 count 파라미터 지정입니다.
Window의 선언
import RxSwift
public func window(
timeSpan: RxTimeInterval,
count: Int,
scheduler: SchedulerType
) -> Observable<Observable<Element>> {
return WindowTimeCount(
source: self.asObservable(),
timeSpan: timeSpan,
count: count,
scheduler: scheduler
)
}
이렇게 Buffer와 선언이 비슷할수가😱
파라미터 시그니처에 대한 설명은 Buffer와 동일하기에 따로 하지 않겠습니다.
여기서 차이는 반환타입입니다.
Buffer는 어레이 옵저버블이면 Window는 어레이가 아닌 하나하나씩인 옵저버블 요소를 방출합니다.
끝!
Window의 사용
import RxSwift
Observable<Int>
.interval(
.seconds(1),
scheduler: MainScheduler.instance
)
.window(
timeSpan: .seconds(3),
count: 5,
scheduler: MainScheduler.instance
)
.take(3)
.subscribe {
if let observable = $0.element {
observable.subscribe {
print($0)
}
}
}
.disposed(by: disposeBag)
// Output
[0, 1, 2]
[3, 4, 5]
[6, 7, 8, 9]
요렇게 한번 보시면, Buffer때의 사용 예제와 동일합니다.
대신 Observable의 element로 출력해서 확인해봤습니다.
Window는 수집한 항목을 배열이 아닌 각각의 옵저버블로 리턴하기에 해당 옵저버블이 어떤걸 방출하고 어느 시점에 completed되는지 파악하는것이 필요합니다.
이렇게 Buffer와 Window에 대해 학습해보았습니다.
어느 상황에서 어떤걸 적재적소에 사용할지 감이 딱 잡히진 않았지만 앞서 배운 Debounce / Throttle / Buffer / Window 모두 적재적소에 사용되는 그날까지🥳
[참고자료]