티스토리 뷰
RxSwift에는 여러 Operator가 있습니다. 그 중 Filtering Operators에 대해 알아보겠습니다!
Filtering Operator를 사용하면 구독자가 원하는 요소만 .next이벤트를 통해 수신할 수 있습니다.
Ignoring Operators
IgnoreElements로 시작하는 RxSwift의 Filtering Operator를 살펴보겠습니다.
ignoreElements()
아래 다이어그램과 같이 ignoreElements는 .next 이벤트 요소를 무시합니다. 하지만 .completed, .error 이벤트와 같은 중지 이벤트는 허용합니다.
let strikes = PublishSubject<String>()
let disposeBag = DisposeBag()
strikes
.ignoreElements()
.subscribe { _ in
print("You're out!")
}
.disposed(by: disposeBag)
strikes.onNext("X")
strikes.onNext("X")
strikes.onNext("X")
strikes.onCompleted()
ignoreElements를 포함해 위와 같은 코드를 작성하면 , 3개의 .next 이벤트 모두 무시하기 때문에 아무 것도 print되지 않습니다.
그 후 .completed 이벤트를 수신 했을 때 "You're out!" 이 출력됩니다.
element(At:)
element(At:)은 아래 그림과 같이 전달되는 이벤트 중 N번째(index는 0부터 시작) 이벤트만 수신하는 Operator입니다.
let strikes = PublishSubject<String>()
let disposeBag = DisposeBag()
strikes
.element(at: 1)
.subscribe { element in
print("event:", element)
}
.disposed(by: disposeBag)
strikes.onNext("1")
strikes.onNext("2")
strikes.onNext("3")
// Result
// print -> event: next(2)
// print -> event: completed
위와 같이 element(at: 1)을 포함한 PublishSubject를 구독하고 , "1", "2", "3" 을 가진 .next 이벤트를 순서대로 전달하면, 2번째 이벤트인 (1번째 index) "2"만 출력하게 됩니다. 그 후 사용자가 원하는 2번째 이벤트를 전달받았기 때문에 "2"를 출력한 후 바로 .ompleted 이벤트가 발생하고 구독이 종료됩니다.
filter
filter는 필터링 요구사항이 한 가지 이상일 때 사용할 수 있습니다.
위 다이어그램처럼 filter의 조건은 Bool 값으로 판단하고, 전달받은 .next 이벤트 중 filter 조건을 만족하는 이벤트만 수신합니다.
let displseBag = DisposeBag()
Observable.of(1,2,3,2,1)
.filter { $0 < 3 }
.subscribe(onNext: {
print($0)
})
.disposed(by: displseBag)
// Result
// print -> 1
// print -> 2
// print -> 2
// print -> 1
filter Operator를 포함해 위와 같은 코드를 작성해보았습니다. filter의 조건 값이 3보다 작은 Int 자료형이기 때문에, Observable로 전달하는 1,2,3,2,1 다섯 개의 이벤트 중 해당 조건을 만족하지 않는 3을 무시하고 1,2,2,1 이벤트만 수신합니다.
let displseBag = DisposeBag()
Observable.of(1,2,3,2,1)
.filter { $0 < 3 && $0 % 2 == 0}
.subscribe(onNext: {
print($0)
})
.disposed(by: displseBag)
// Result
// print -> 2
// print -> 2
filter Operator는 결과가 Bool 형을 만족하는 한가지 이상의 조건을 포함할 수 있기 때문에 위와 같이 "3보다 작고, 짝수인 수" 라는 두 개의 조건을 필터링 할 수도 있습니다. 그럼, 해당 조건을 만족하는 2를 전달하는 2개의 .next 이벤트만 수신하게 됩니다.
Skipping Operators
어떤 순서나 조건에 따라 이벤트를 Skip 할 수 있는 Skipping Operators에 대해 살펴보겠습니다.
skip
skip Operator는 skip 할 이벤트의 갯수를 인자로 받습니다. 그럼 Observable에 전달되는 .next 이벤트 중 해당 갯수 만큼의 이벤트를 무시한 후 그 다음 이벤트 부터 수신하게 됩니다.
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.skip(2)
.subscribe(onNext:{
print("event:", $0)
})
.disposed(by: disposeBag)
// Result
// print -> event: C
// print -> event: D
// print -> event: E
// print -> event: F
위의 코드에서는 A부터 F까지 6개의 .next 이벤트를 전달받는 Observable이 skip(2) Operator를 포함하고 있습니다.
Observable은 전달받은 .next 이벤트 중 앞에서 2개의 이벤트를 무시한 후 그 다음 이벤트 부터 전달받게 되기에 A와 B 이벤트는 무시한 후 C부터 F까지의 이벤트를 출력합니다.
skipWhile
구독하는 동안 조건을 만족하는 모든 이벤트를 필터링하는 filter와 달리 skipWhile은 조건이 false가 되기 전까지만 필터링합니다.
이전에 skipWhile로 쓰던 Operator가 deprecated 되면서 skip(while:) 형식으로 사용해야 합니다!
let disposeBag = DisposeBag()
Observable.of(2, 2, 3, 4, 4)
.skip(while: {
return $0 % 2 == 0
})
.subscribe(onNext: {
print("element:", $0)
})
.disposed(by: disposeBag)
// Result
// print -> element: 3
// print -> element: 4
// print -> element: 4
위와 같이 skip(while:) 형식 (skipWhile) 을 포함해 Observable을 구독하면, .next 요소가 짝수값인 동안 이벤트를 skip 하고 최초로 홀수값인 이벤트를 수신한 이후 부터는 모든 이벤트를 수신하게 됩니다.
skipUntil
위에서 살펴본 Operator들은 해당 Observable이 수신하는 이벤트에 대한 고정 조건에 대해서 이루어졌습니다.
하지만 skipUntil은 다른 Observable에 기반해 이벤트를 필터링 할 수 있습니다.
let disposeBag = DisposeBag()
let subject = PublishSubject<String>()
let trigger = PublishSubject<String>()
subject
.skip(until: trigger)
.subscribe(onNext: {
print("element:", $0)
})
.disposed(by: disposeBag)
subject.onNext("A")
subject.onNext("B")
trigger.onNext("X")
subject.onNext("C")
// Result
// print -> element: C
subject와 trigger 2개의 Observable 을 생성하고, subject를 구독하면서 skip(until: trigger)를 추가했습니다.
그 후 subject에 A, B 2개의 .next 이벤트를 전달했지만, trigger Observable이 시동하지 않았기 때문에 해당 이벤트들은 무시됩니다.
그 후 trigger에 X 이벤트를 전달하며 trigger Observable이 시동되었고, 그 후에 subject로 전달되는 C 이벤트는 출력됩니다.
Taking Operators
Taking Operator는 Skip Operator와 반대로 어떤 요소를 취하고 싶을 때 사용합니다.
take
take는 원하는 갯수만큼의 .next 이벤트를 취할 때 사용합니다.
let disposeBag = DisposeBag()
Observable.of(2, 2, 4, 4, 6, 6)
.take(3)
.subscribe(
onNext: {
print("element: ", $0)
},
onCompleted: {
print("completed")
})
.disposed(by: disposeBag)
// Result
// print -> element: 2
// print -> element: 2
// print -> element: 4
// print -> completed
위와 같이 take(3)을 포함한 코드를 포함하면, Observable로 전달되는 .next 이벤트 중 앞에서 3개의 요소만 취하게 됩니다.
해당 코드의 결과로는 2,2,4 가 출력되고 Observable이 종료됩니다.
takeWhile
takeWhile은 해당 조건에 참인 동안 동작하고, 해당 조건에 거짓인 .next 이벤트가 전달된 직 후 .completed 이벤트가 발생하고 이후로 전달되는 .next 이벤트들은 수신하지 않습니다.
let disposeBag = DisposeBag()
Observable.of(2, 2, 4, 4, 1, 1)
.take(while: {
return $0 < 3
})
.subscribe(
onNext: {
print("element: ", $0)
},
onCompleted: {
print("completed")
})
.disposed(by: disposeBag)
// Result
// print -> element: 2
// print -> element: 2
// print -> completed
takeWhile에 3보다 작은 값을 조건으로 포함하여 위와 같은 코드를 작성하였습니다. 첫번째와 두번째 .next 이벤트로 전달된 2를 모두 수신하고 그 후 4가 전달될 때 3보다 작다는 조건을 만족하지 못하므로 .completed 이벤트가 발생하고 이 후에 전달되는 .next 이벤트들은 수신하지 않게 됩니다.
takeUntil
takeUntil은 trigger Observable이 시동하기 전까지만 .next 이벤트를 방출하는 Operator입니다.
let disposeBag = DisposeBag()
let subject = PublishSubject<String>()
let trigger = PublishSubject<String>()
subject
.take(until: trigger)
.subscribe(
onNext: {
print("element: ", $0)
},
onCompleted: {
print("completed")
}
)
.disposed(by: disposeBag)
subject.onNext("A")
subject.onNext("B")
trigger.onNext("X")
subject.onNext("C")
// Result
// print -> element: A
// print -> element: B
// print -> completed
위와 같이 메인 subject와 trigger Subject 두 개를 생성하고, 메인 subject에 take(until: trigger) 코드를 포함해 구독하였습니다.
그 후 A, B 두 개의 .next 이벤트를 subject로 전달하면 해당 이벤트 들을 수신하여 출력합니다.
그 후에 .next로 X를 전달하여 trigger를 시동하면, 메인 subject는 .completed 이벤트를 방출하며 종료되고 그 후에 전달되는 이벤트는 수신하지 못하게 됩니다.
Distinct Operators
Distinct Operators는 중복되는 값들의 연속을 막아줍니다.
distinctUntilChanged
distinctUntilChanged Operator은 이름 그대로, 값이 바뀌기 전까지 연속되는 중복값들을 막아줍니다.
아래 다이어그램과 같이 연속으로 전달되는 같은 값 중 맨 첫번째 값만을 취하고, 그 후에 다른 값이 전달되면 그 값을 취합니다.
let disposeBag = DisposeBag()
Observable.of("A", "A", "B", "B", "A")
.distinctUntilChanged()
.subscribe(onNext: {
print("element: ", $0)
})
.disposed(by: disposeBag)
// Result
// print -> element: A
// print -> element: B
// print -> element: A
위의 코드를 보면, 연속으로 같은 값을 취하지 않는 결과를 볼 수 있습니다.
distinctUntilChanged로 인해 출력되지 않은 값을 괄호를 이용해 표현하면 A(A)B(B)A 와 같이 나타낼 수 있습니다.
distinctUntilChanged(_:)
distinctUntilChanged에 조건문을 포함하면 직접 비교로직을 구현할 수 있습니다.
let disposeBag = DisposeBag()
Observable.of("AA", "AB", "BB", "BC", "AB")
.distinctUntilChanged {
return $0.prefix(1) == $1.prefix(1)
}
.subscribe(onNext: {
print("element: ", $0)
})
.disposed(by: disposeBag)
// Result
// print -> element: AA
// print -> element: BB
// print -> element: AB
위와 같은 코드를 작성해 보았습니다. distinctUntilChanged의 조건으로 각 String 값의 첫번째 문자가 같은 .next 이벤트는 막아주는 구문을 포함하겠습니다.
그럼 AA 이벤트 이후 전달된 AB 이벤트는 똑같이 A로 시작되기에 방출되지 못하고, BB 이벤트 이후 BC 이벤트도 이전의 이벤트와 같이 B로 시작하기에 방출되지 못합니다.
참고 : Reactive Programming with Swift By the raywenderlich.com Tutorial Team
'iOS > RxSwift' 카테고리의 다른 글
RxSwift - Relay (0) | 2022.03.05 |
---|---|
RxSwift - Subject (0) | 2022.03.04 |
RxSwift - Disposable, DisposeBag (0) | 2022.03.01 |
RxSwift - Infallible (0) | 2022.02.28 |
RxSwift - Observables, Observers (0) | 2022.02.27 |
- Total
- Today
- Yesterday
- SWEA
- Lottie
- blendshapes
- ios
- 백준온라인저지
- Kotlin
- infallible
- C++
- Neo4j
- ARKit
- 카카오인턴십
- Swift
- DispatchQueue
- Swift unowned
- boj
- cocoapods
- disposeBag
- 알고리즘
- 백준
- 코코아팟
- Reactivex
- rxswift6
- coreml
- GraphDB
- 안드로이드
- SwiftUI
- rxswift
- blendshape
- Swift weak
- 프로그래머스
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |