RxSwift - Filtering Operators
안녕하세요. 그린입니다🟢
이번 포스팅에서는 RxSwift의 Filtering Operator들에 대해 학습해보겠습니다🙋🏻
Filtering Operator?
이름에서부터 어떤건지 느낌이오죠?
필터를 해주는겁니다.
어떤걸 필터를 해주냐?
next 이벤트를 통해 넘어온 값들에 대해 필터를 해줍니다.
즉 해당 오퍼레이터를 통해 넘어온 값들에 대해 다 처리하지 않고 원하는 값만 골라 처리할 수 있습니다👍
Filtering Operator 종류
크게 4가지의 종류로 나눠볼 수 있습니다.
1. Ignoring Operator
2. Skipping Operator
3. Taking Operator
4. Distinct Operator
그럼 4가지 종류가 있다고 했으니 하나씩 자세하게 어떤 오퍼레이터들을 담고 있는지 알아보겠습니다🙌
세부적으로 더 많은 종류가 있지만 가장 자주 쓰이고 대표적인것 위주로 먼저 학습할께요!
Ignoing Operator
해당 오퍼레이터는 말 그대로 어떤 값을 무시할때 쓰입니다.
즉 next로 넘어온 값들에 대해 어떤 조건을 통해 무시할 수 있습니다.
크게 3가지의 오퍼레이터가 있습니다.
1. ignoreElement()
해당 그림을 보면 값들이 방출되어도 무시되고 스트림에 등록되지 않는걸 볼 수 있습니다.
즉 next로 넘어온 값들에 대해 무시하고 error나 completed 이벤트는 무시하지 않습니다.
간단히 코드로 볼께요!
let subject = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.ignoreElements()
.subscribe({ _ in
print("Finished!")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
subject.onCompleted()
// Finished!
자 이렇게 어떤 값들이 들어와도 프린트문이 동작하지 않다고 completed시에만 동작합니다~!
2. elementAt
이런식으로 원하는 인자 즉 인덱스 값을 넣어주면 해당 전까지의 값들은 무시하고
해당 인덱스를 가진 값은 방출하게 됩니다.
코드로 보시죠!
let subject = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.elementAt(3)
.subscribe({ num in
print("\(num Finished!)")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
subject.onCompleted()
// 4 Finished!
이렇게 1~3까지 즉 3인덱스 전까지는 무시하고 3의 인덱스를 가진 4번째 요소의 값만 방출되었습니다.
3. filter
필터는 우리가 알고있는 고차함수의 filter와 동일한 역할을 합니다.
조건에 해당되는 값만 방출합니다.
코드로 보시죠!
let subject = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.filter({ (num) -> Bool in
num < 3
)}
.subscribe({ num in
print("\(num Finished!)")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
subject.onCompleted()
// 3 Finished!
// 4 Finished!
이렇게 3이상만 필터를 먹여 1과 2는 무시되고 3과 4의 값만 방출됩니다.
Skipping Operator
직역하면 어떤걸 스킵한다는 뜻인데요. 즉 건너띈다는 뜻이죠.
그럼 어떤 조건으로 스킵하는지에 따라 나뉠 수 있겠네요!
하나씩 알아보시죠🙌
1. skip
인자로 주어진 수만큼의 값을 스킵할 수 있습니다.
코드로 보시죠.
let subject = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.skip(3)
.subscribe({ num in
print("\(num Finished!)")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
subject.onCompleted()
// 4 Finished!
3개를 스킵한다고 해주었기에 1~3까지는 스킵되고 4가 방출됩니다.
2. skipWhile
특정 조건이 부합하기전에 들어온 값들에 대해서는 스킵합니다.
while문과 비슷하다고 생각되네요!
이것도 코드로~👍
let subject = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.skipWhile({ (num) -> Bool in
num == 3
)}
.subscribe({ num in
print("\(num Finished!)")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
subject.onCompleted()
// 3 Finished!
// 4 Finished!
자 여기선 3이여야 되는 조건을 주었는데 4는 왜 방출될까요?
바로 skipWhile이였기에 3이 들어와서 조건이 맞아지는순간 스킵은 끝납니다.
즉 4가 먼저 들어왔다면 방출이 되지 않았을거에요!
이점이 filter와는 사뭇 다른점입니다☺️
3. skipUntil
조금 어려워보일 수 있는데요.
다른 옵저버블에서 방출되기전에는 모든 값을 스킵하는것입니다.
잘 이해가 안가죠?
코드로 보시죠!
let subject = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.skipUntil(subject2)
.subscribe({ num in
print("\(num Finished!)")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject2.onNext(10)
subject.onNext(3)
subject2.onNext(11)
subject.onNext(4)
subject.onCompleted()
// 3 Finished!
// 4 Finished!
이렇게 1~2는 subject2가 동작하지 않았으니 스킵되고 이후 값들은 모두 방출됩니다.
Taking Operator
take는 직역하면 '가져온다'라는 뜻이 있습니다.
즉 어떤 조건에 맞는 값들을 가져와 방출하는겁니다.
위에서 계속 언급했던 Skip Operator와는 반대되는 개념입니다.
1. take
인자값으로 몇개의 값을 가져올지 정해줍니다.
위 그림처럼 2로 주면 처음으로부터 2개의 값을 가져오고 종료합니다.
코드로 보시죠!
let subject = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.take(2)
.subscribe({ num in
print("\(num Finished!)")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
// 1 Finished!
// 2 Finished!
처음 방출되는 값인 1과 그다음인 2를 방출하고 끝납니다.
2. takeWhile
skipWhile과 동일한 동작인데 반대입니다.
즉 조건을 만나기전까지의 이벤트 값만 방출하고 그 뒤론 무시합니다.
이것도 코드로!
let subject = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.takeWhile({ (num) -> Bool in
num == 3
)}
.subscribe({ num in
print("\(num Finished!)")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
// 1 Finished!
// 2 Finished!
3일때의 조건을 걸어주어 그 전인 1과 2 값만 방출되는걸 볼 수 있습니다.
3. takeUntil
이것도 SkipUntil과 비슷하지만 반대의 개념입니다.
어떤 다른 옵저버블의 실행이 있기전까지 가져오고 그 뒤론 종료됩니다.
이것도 마찬가지로 코드로!!
let subject = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
let disposeBag = DisposeBag()
subject
.takeUntil(subject2)
.subscribe({ num in
print("\(num Finished!)")
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject2.onNext(10)
subject.onNext(3)
subject2.onNext(11)
subject.onNext(4)
// 1 Finished!
// 2 Finished!
이것도 SkipUntil과 비교하면 참 쉽죠?💁🏻
Distinct Operator
해당 오퍼레이터는 중복값을 제거해주는 역할을 합니다.
쉽게 사용될 수 있는데 함께 보시죠🥳
1. distinctUntilChanged
1, 2, 3의 값들이 중복으로 들어와도 중복된 값은 없애줍니다.
코드를 보면 더 이해가 쉽습니다ㅎㅎ
let disposeBag = DisposeBag()
Observable.of(1, 1, 2, 2, 3, 3)
.distinctUntilChanged()
.subscribe(onNext: { num in
print("\(num) Finished!")
})
.disposed(by: disposeBag)
// 1 Finished!
// 2 Finished!
// 3 Finished!
이렇게 중복을 제거해줍니다.
2. distinctUntilChanged(_:)
중복을 제거해주는건 동일하지만 클로저를 주어 조금 더 커스텀하게 만들 수 있습니다.
클로저에 원하는 로직을 넣어주면 됩니다🙏🏻
마무리
이렇게 이번 포스팅에서는 방출되는 이벤트에 대한 값들을 원하는것만 가져올 수 있는 오퍼레이터에 대해 알아봤습니다!
고차함수에 익숙하다면 자연스럽게 사용할 수 있을 정도로 러닝커브가 높진 않아보입니다만...
다만..! 적재적소에 어떤걸 쓸지는 참 어렵겠죠😅
눈감고 쓸 수 있는 그날까지 열심히 달려봐요🏃🏻
[참고자료]
http://reactivex.io/documentation/operators/distinct.html