제네릭 구조체 | 두 개의 Publisher로부터 최신의 요소를 전달받고 조합하는 Publisher
이니셜라이저는 조합할 두 개의 Publisher를 받는다.
조합할 모든 Publisher의 에러 타입은 같아야 한다.
두 개의 Publisher에서 최신의 요소를 발행했을 때 이들을 조합하는 동작을 원할 때 사용할 수 있다.
예를 들어 두 개의 입력 폼이 있고 모두 값이 입력되어야 버튼을 활성화해야 한다는 요구사항이 있을 때 이 동작을 사용할 수 있다. 두 개의 입력에 대한 Publisher에서 모두 값을 발행해야 하기 때문이다.
comnbineLatest
오퍼레이터와 관련이 있다.
let aSubject = PassthroughSubject<Int, Never>()
let bSubject = PassthroughSubject<Int, Never>()
// Publishers.CombineLatest Publisher
Publishers
.CombineLatest(aSubject, bSubject)
.sink(receiveCompletion: { completion in
switch completion {
case .failure:
print("Combine CombineLatest Error")
case .finished:
print("Combine CombineLatest Finish")
}
}, receiveValue: { value in
print("Combine CombineLatest : \(value)")
})
.store(in: &cancellables)
// Combine CombineLatest : (2, 3)
// Combine CombineLatest : (2, 4)
// Combine CombineLatest Finish
// combineLatest Operator
aSubject
.combineLatest(bSubject)
.sink(receiveCompletion: { completion in
switch completion {
case .failure:
print("Combine CombineLatest Error")
case .finished:
print("Combine CombineLatest Finish")
}
}, receiveValue: { value in
print("Combine CombineLatest : \(value)")
})
.store(in: &cancellables)
// Combine CombineLatest : (2, 3)
// Combine CombineLatest : (2, 4)
// Combine CombineLatest Finish
aSubject
.combineLatest(bSubject) { $0 * $1 }
.sink(receiveCompletion: { completion in
switch completion {
case .failure:
print("Combine CombineLatest Error")
case .finished:
print("Combine CombineLatest Finish")
}
}, receiveValue: { value in
print("Combine CombineLatest : \(value)")
})
.store(in: &cancellables)
// Combine CombineLatest : 6
// Combine CombineLatest : 8
// Combine CombineLatest Finish
// 1
aSubject.send(1)
// 2
aSubject.send(2)
// 3
bSubject.send(3)
// 4
bSubject.send(4)
두 개의 Subject로부터 최신의 요소를 전달받고 조합하도록 하였다.
변환 클로저를 적용하지 않은 코드는 다음과 같이 동작한다.
1의 실행에 의해 aSubject
에 1의 값을 전달한다. bSubject
에 값이 전달된 적이 없으므로 해당 Publisher는 값을 내지 않는다.
2의 실행에 의해 aSubject
에 2의 값을 전달한다. bSubject
에 값이 전달된 적이 없으므로 해당 Publisher는 값을 내지 않는다.
3의 실행에 의해 bSubject
에 3의 값을 전달한다. aSubject
에 값이 전달된 적이 있으므로 해당 Publisher는 aSubject
의 최신 값인 2와 bSubject
의 최신 값인 3을 튜플의 형태로 조합하여 (2, 3)의 값을 낸다.
4의 실행에 의해 bSubject
에 4의 값을 전달한다. aSubject
에 값이 전달된 적이 있으므로 해당 Publisher는 aSubject
의 최신 값인 2와 bSubject
의 최신 값인 4를 튜플의 형태로 조합하여 (2, 4)의 값을 낸다.
변환 클로저를 적용한 코드는 다음과 같이 동작한다.
1의 실행에 의해 aSubject
에 1의 값을 전달한다. bSubject
에 값이 전달된 적이 없으므로 해당 Publisher는 값을 내지 않는다.
2의 실행에 의해 aSubject
에 2의 값을 전달한다. bSubject
에 값이 전달된 적이 없으므로 해당 Publisher는 값을 내지 않는다.
3의 실행에 의해 bSunject
에 3의 값을 전달한다. aSubject
에 값이 전달된 적이 있으므로 해당 Publisher는 aSubject
의 최신 값인 2와 bSubject
의 최신 값인 3을 곱하여 6의 값을 낸다.
4의 실행에 의해 bSunject
에 4의 값을 전달한다. aSubject
에 값이 전달된 적이 있으므로 해당 Publisher는 aSubject
의 최신 값인 2와 bSubject
의 최신 값인 4를 곱하여 8의 값을 낸다.
RxSwift
combineLatest
오퍼레이터를 사용하여 구현할 수 있다.
let aSubject = PublishSubject<Int>()
let bSubject = PublishSubject<Int>()
Observable.combineLatest(aSubject, bSubject)
.subscribe(onNext: { value in
print("RxSwift CombineLatest : \(value)")
}, onError: { _ in
print("RxSwift CombineLatest Error")
}, onCompleted: {
print("RxSwift CombineLatest Finish")
})
.disposed(by: disposeBag)
aSubject.onNext(1)
aSubject.onNext(2)
bSubject.onNext(3)
bSubject.onNext(4)
// RxSwift CombineLatest : (2, 3)
// RxSwift CombineLatest : (2, 4)
ReactiveSwift
combineLatest
오퍼레이터를 사용하여 구현할 수 있다.
let aProperty = MutableProperty<Int>(0)
let bProperty = MutableProperty<Int>(0)
aProperty.signal
.combineLatest(with: bProperty.signal)
.observe { event in
switch event {
case let .value(value):
print("ReactiveSwift CombineLatest : \(value)")
case .failed:
print("ReactiveSwift CombineLatest Error")
case .completed:
print("ReactiveSwift CombineLatest Finish")
default:
break
}
}
aProperty.value = 1
aProperty.value = 2
bProperty.value = 3
bProperty.value = 4
// ReactiveSwift CombineLatest : (2, 3)
// ReactiveSwift CombineLatest : (2, 4)
// ReactiveSwift CombineLatest Finish
참고
ReactiveX - Operators - CombineLatest