본 게시물은 Florent Pillet, Junior Bontognali, Marin Todorov, Scott Gardner - RxSwift. Reactive Programming with Swift (2017, Razeware LLC) 책과 ReactiveX 사이트를 기반으로 작성되었습니다.
RxSwift를 공부하는 데에 이 책을 읽으면 좋겠다고 생각하였고, 단지 읽기만 하는 것보다 한국어로 직접 정리해놓으면 더 기억하기 좋을 것 같아 게시물을 작성하게 되었습니다.
이번 게시물에서는 마블 다이어그램과, 마블 다이어그램에 해당하는 메서드 예시를 중점으로 정리하였습니다.
챕터 이름에서 알 수 있듯이, 이번 게시물에서는 원하는 값을 얻기위해 필터링을 하는 Filtering Operator들을 알아보겠습니다.
👉ignoreElements, elementAt, filter, skip, skipWhile, skipUntil, take, takeWhile, enumerated, takeUntil, distinctUntilChanged
A. Ignoring Operators
I. ignoreElements( )
ignoreElements는 next 이벤트를 무시하고 completed나 error 이벤트와 같은 종료 이벤트만 허용합니다. 아래 예시를 보면 next 이벤트에서는 반응하지 않다가 completed 이벤트에 반응하는 것을 알 수 있습니다.
let publishSubject = PublishSubject<String>()
let disposeBag = DisposeBag()
publishSubject
.ignoreElements()
.subscribe { _ in
print("hello, world!")
}
.addDisposableTo(disposeBag)
publishSubject.onNext("X")
publishSubject.onNext("X")
publishSubject.onNext("X")
publishSubject.onCompleted()
[ 출력 ]
hello, world!
II. elementAt(n)
우리는 가끔 특정한 순서의 element, 즉 n번째 방출되는 element만 처리하고 싶은 경우가 있을 수 있습니다. 이 때 elementAt(n)을 사용하면, 해당 index에 해당하는 element만을 방출하고 나머지는 무시합니다.
let publishSubject = PublishSubject<String>()
let disposeBag = DisposeBag()
publishSubject
.elementAt(1)
.subscribe(
onNext: { _ in
print("hello, world!")
}
)
.addDisposableTo(disposeBag)
publishSubject.onNext("X")
publishSubject.onNext("X")
publishSubject.onNext("X")
[ 출력 ]
hello, world!
III. filter(조건)
앞서 살펴보았던 ignoreElements와 elementAt은 방출되는 element를 필터링합니다. 만약 우리가 필터링 하고싶은 요구사항이 한 가지 이상일 때는 filter를 사용하면 됩니다. 아래 예시를 살펴보면, 값이 3 미만인 element들만 방출되는 것을 알 수 있습니다.
let disposeBag = DisposeBag()
Observable.of(1,2,3,4,5,6)
.filter { value in
value < 3
}
. subscribe(
onNext: {
print($0)
}
)
.addDisposableTo(disposeBag)
[ 출력 ]
1
2
B. Skipping Operators
I. skip(n)
우리는 가끔 몇 개의 element들을 skip하고 싶을 때가 있습니다. 예를 들어 날씨 예보의 경우, 특정 시간 이후의 시간별 데이터를 받고 싶지 않을 수 있습니다. skip 연산자는 우리가 첫 element부터 우리가 파라미터로 설정한 element까지 skip할 수 있도록 합니다.
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.skip(3)
.subscribe(
onNext: {
print($0)
}
)
.addDisposableTo(disposeBag)
[ 출력 ]
D
E
F
II. skipWhile(조건)
subscribe하는 동안 모든 element들을 필터링하는 filter와 달리, skipWhile은 어떠한 element를 skip하지 않을 때까지 skip하고 종료하는 연산자입니다. 이게 무슨 말이냐! 하면.. 어떤 skipWhile 조건에 맞는 element들을 skip하다가, 어느순간 그 조건에 맞지 않는 element는 방출시키게 되겠죠? 그럼 이때부터는 skipWhile 조건이라는 제약이 풀려서 이후부터는 다시 조건에 맞는 element가 들어오더라도 신경쓰지 않고 방출한다~ 이 말입니다!
아래 예시를 보면, 처음에 int % 2 == 1 이라는 조건에 맞는 1과 3은 skip되었는데, 조건에 맞지 않는 4가 방출된 이후부터는 조건과 상관 없이 방출이 되고 있는 것을 확인할 수 있습니다.
let disposeBag = DisposeBag()
Observable.of(1,3,4,6,5,7,8)
.skipWhile({ (int) -> Bool in
int % 2 == 1
})
.subscribe(
onNext: {
print($0)
}
)
.disposed(by: disposeBag)
[ 출력 ]
4
6
5
7
8
III. skipUntil(otherObservable)
앞서 살펴보았던 Skip Operator들은 고정된 조건에서 이루어졌습니다. 그럼 만약 다른 Observable에 기반한 element들을 dynamic하게 필터링하고 싶다면 어떻게 해야할까요? skipUntil을 사용하면 다른 Observable이 동작할 때까지 현재 Observable에서 방출하는 이벤트들을 skip합니다.
let disposeBag = DisposeBag()
let subject = PublishSubject<String>()
let trigger = PublishSubject<String>()
subject
.skipUntil(trigger)
.subscribe(
onNext: {
print($0)
}
)
.disposed(by: disposeBag)
subject.onNext("A")
subject.onNext("B")
trigger.onNext("X")
subject.onNext("C")
[ 출력 ]
C
C. Taking Operators
I. take(n)
Taking은 Skipping의 반대 개념으로 생각하면 되는데, 우리가 어떤 element들을 취하고 싶을 때 take를 사용합니다. 예시를 보면, take로 설정한 처음 2개의 element를 취한 것을 볼 수 있습니다.
let disposeBag = DisposeBag()
Observable.of(1,2,3,4,5)
.take(2)
.subscribe(
onNext: {
print($0)
}
)
.disposed(by: disposeBag)
[ 출력 ]
1
2
II. takeWhile(조건)
takeWhile은 skipWhile처럼 작동하는데, 위 마블다이어그램과 같이 takeWhile 구문 내에서 설정한 조건에서 true에 해당하는 값을 방출하게 됩니다.
III. enumerated( )
방출된 element의 index를 참고하고 싶은 경우가 있는데, enumerated 연산자를 사용하면 기존 swift의 enumerated 메서드와 유사하게 Observable에서 나오는 각 element의 index와 값을 포함하는 튜플을 생성하게 됩니다.
let disposeBag = DisposeBag()
Observable.of(1,2,3)
.enumerated()
.takeWhile({ index, value in
value > 1 && index > 1
})
.map {
$0.element
}
.subscribe(
onNext: {
print($0)
}
)
.disposed(by: disposeBag)
[ 출력 ]
3
IV. takeUntil(otherObservable)
skipUntil은 trigger 역할을 하는 Observable이 subscribe 될 때까지 skip되었다면, takeUntil은 trigger 역할을 하는 Observable이 subscribe되기 전까지의 이벤트값만 받게 됩니다.
let disposeBag = DisposeBag()
let subject = PublishSubject<String>()
let trigger = PublishSubject<String>()
subject
.takeUntil(trigger)
.subscribe(
onNext: {
print($0)
}
)
.disposed(by: disposeBag)
subject.onNext("1")
subject.onNext("2")
trigger.onNext("X")
subject.onNext("3")
[ 출력 ]
1
2
D. Distinct Operators
I. distinctUntilChanged( )
중복되어 이어지는 값을 막아줍니다. 그렇기 때문에 위 마블다이어그램을 보면 연속되어 중복되는 2는 방출되지 않고, 이후에 나오는 1은 중복이긴 하지만 연속되어 반복된 것이 아니기 때문에 방출됩니다.
let disposeBag = DisposeBag()
Observable.of(1, 2, 2, 1)
.distinctUntilChanged()
.subscribe(
onNext: {
print($0)
}
)
.disposed(by: disposeBag)
[ 출력 ]
1
2
1
II. distinctUntilChanged(_:)
위에서 살펴본 distinctUntilChanged는 기본적으로 구현된 로직을 바탕으로 중복을 확인합니다. 하지만 만약 우리가 커스텀한 비교로직을 사용하고 싶다면 distinctUntilChanged(_:)를 사용하면 됩니다.
struct Model {
var value: Int
}
// ----------------------
let disposeBag = DisposeBag()
let model1 = Model(value: 1)
let model2 = Model(value: 1)
let model3 = Model(value: 2)
Observable<Model>.of(model1, model2, model3)
.distinctUntilChanged({ o1, o2 in
o1.value == o2.value
})
.subscribe(
onNext: {
print($0.value)
}
)
.addDisposableTo(disposeBag)
[ 출력 ]
1
2
'iOS > RxSwift' 카테고리의 다른 글
Ch7. Transforming Operators (0) | 2023.02.24 |
---|---|
RxSwift. Traits가 뭘까? (Single, Maybe, Completable) (0) | 2023.02.24 |
Ch3. Subjects (0) | 2023.02.24 |
Ch2. Observable (0) | 2023.02.24 |
Ch9. Combining Operators (1) | 2021.01.13 |
댓글