ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RxSwift - Filtering Operators
    RxSwift 2021. 11. 8. 09:56

    안녕하세요. 그린입니다🟢

    이번 포스팅에서는 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

     

    ReactiveX - Distinct operator

    In RxJS, the distinct operator has two optional parameters: a function that accepts an item emitted by the source Observable and returns a key which will be used instead of the item itself when comparing two items for distinctness a function that accepts t

    reactivex.io

    https://github.com/fimuxd/RxSwift/blob/master/Lectures/05_Filtering%20Operators/Ch5.%20FilteringOperators.md

     

    GitHub - fimuxd/RxSwift: RxSwift를 스터디하는 공간

    RxSwift를 스터디하는 공간. Contribute to fimuxd/RxSwift development by creating an account on GitHub.

    github.com

     

    'RxSwift' 카테고리의 다른 글

    RxSwift - Combining Operator  (0) 2021.11.12
    RxSwift - Transforming Operator  (0) 2021.11.10
    RxSwift - Subject  (0) 2021.11.03
    RxSwift - Observable  (0) 2021.10.30
    RxSwift - Zip  (0) 2021.10.13
Designed by Tistory.