distinctUntilChanged
옵저버블에서 방출하는 이벤트를 순서대로 비교한 다음 이전 이벤트와 동일하다면 방출하지 않는다.
이벤트를 비교할 때에는 비교 연산자를 사용해서 포함되어있는 값을 비교한다.
let numbers = [1, 1, 3, 2, 2, 3, 1, 5, 5, 7, 7, 7]
Observable.from(numbers)
.distinctUntilChanged()
.subscribe{ print($0)}
.disposed(by: disposeBag)
//next(1)
//next(3)
//next(2)
//next(3)
//next(1)
//next(5)
//next(7)
//completed
동일한 요소가 연속적으로 방출된게 아니라면 방출한다.
이전 이벤트와 다르다면 이미 방출했더라도 그대로 방출한다.
만약 이벤트를 비교하는 코드를 직접 구현하고 싶다면 클로저나 키패스를 파라미터로 받는 연산자를 사용한다.
클로저를 파라미터로 받는다.
옵저버블이 방출한 NextEvent에 포함된 값을 파라미터로 받는다. 두 값이 같다면 true를 리턴하고 다르다면 falsef를 리턴한다.
클로저가 리턴하는 값을 사용해서 이벤트를 비교한다.
.distinctUntilChanged{ !$0.isMultiple(of: 2) && !$1.isMultiple(of: 2) }
이렇게 하면 실제 같은값이 아니라 값이 홀수면 그냥 같은 값으로 판단한다. 전과 지금의 값이 모두 홀수면 true가 되어 방출하지 않게되므로 연속된 홀수를 방출하지 않는다. 반대로 짝수는 모두 false가 되니까 옵저버블이 발생하는 짝수는 그대로 방출한다.
튜플의 비교
keySelector을 파라미터로 갖는 distinctUntilChanged는 클로저를 파라미터로 받지만 이전과 다르다. 파라미터에는 Nextevent에 전달된 값 하나가 전달되고 리턴형은 key로 되어있다.
key는 Equatable을 채용한 타입이다.
((Int,String))으로 전달되는 값은 전달된 값들에 따라 달라지는데 보통 튜플처럼 여러값을 가지고있는 컴포넌트 벨류이고 클로저는 이 중에서 비교할 하나의 값을 리턴한다.
그리고 리턴하는 값은 반드시 Equatable을 채용한 값이 되어야 한다.
let tuples = [(1, "하나"), (1, "일"), (1, "one")]
Observable.from(tuples)
.distinctUntilChanged{ $0.0 }
.subscribe{ print($0) }
//next((1, "하나"))
//completed
첫 번째 값이 모두 1로 동일하기 때문에 처음만 방출되고 모두 무시된다.
let tuples = [(1, "하나"), (1, "일"), (1, "one")]
Observable.from(tuples)
.distinctUntilChanged{ $0.1 }
.subscribe{ print($0) }
//next((1, "하나"))
//next((1, "일"))
//next((1, "one"))
//completed
두번째 값들은 모두 다른 값들이기 때문에 방출된다.
KeyPath를 사용해서 키를 기준으로 이벤트를 비교할 수 있다
let persons = [
Person(name: "Sam", age: 12),
Person(name: "Paul", age: 12),
Person(name: "Tim", age: 56)
]
Observable.from(persons)
.distinctUntilChanged(at: \.age)
.subscribe{print($0)}
.disposed(by: disposeBag)
//next(Person(name: "Sam", age: 12))
//next(Person(name: "Tim", age: 56))
//completed
키패스는 age로 지정되었으므로 Sam과 나이가 같은 Paul은 구독자로 전달되지 않았다.