내가 처음 Combine을 공부할 때 Publisher은 무조건 값을 소유 해야 하고 해당 값이 어떤 이벤트에 의해서 변화 할 때 subscriber에 값을 방출하는 것인 줄 잘못 알고 있었다.
하지만 combine의 값 방출 시점은 값의 변화가 아닌 이벤트 발생 시점과 더 가깝다는 사실을 알게 되었다.
만약 이벤트 발생시점을 외부에서 호출을 통해 제어하고 싶다면 어떻게 해야할까?
이런 경우에 사용 할 수 있는 것이 subject이다.
A publisher that exposes a method for outside callers to publish elements.
외부 호출자를 통해 값을 방출시키기 위한 함수를 노출시키는 puslisher이다.
A subject is a publisher that you can use to ”inject” values into a stream, by calling its send(_:) method. This can be useful for adapting existing imperative code to the Combine model.
subject는 send메서드를 호출함으로써 스트림에 값을 삽입할 수 있는 publisher이다.
이것은 기존 명령형 코드를 combine모델에 적용하는데 유용할 수 있다.
PassthroughSubject
하위 subscriber에게 브로트캐스트 방식으로 값을 전파하는 publisher이다.
CurrentValueSubject
내부에 값을 가지고 있고 내부 값이 변화하면 하위 subscriber들에게 값을 전파한다.
PassthroughSubject는 send메서드를 통해 들어온 값은 단순히 방출시키는 역활만 한다면
CurrentValueSubject는 send메서드를 통해 들어온 값을 내부에 저장하고 저장된 값을 방출시키는 과정을 거친다.
출력결과를 보면 두가지 Subject모두 sub1을 생성하고 .finished값을 방출한다.
이때 CurrentValueSubject는 값을 소유하기 때문에 sub1을 생성한 직후 subject에 저장된 초기값을 바로 방출하지만 PassThroughSubject는 completion결과만 출력되는 것을 볼수있다.
PassThroughSubject예제
func callPassthrough(){
let passthroughSubject = PassthroughSubject<String, Never>()
let sub1 = passthroughSubject
.sink(receiveCompletion: { print("1 번째 sink completion: \($0)") },
receiveValue: { print("1 번째 sink value: \($0)") })
passthroughSubject.send(completion: .finished)
let sub2 = passthroughSubject
.sink(receiveCompletion: { print("2 번째 sink completion: \($0)") },
receiveValue: { print("2 번째 sink value: \($0)") })
// 현재 Subscriber들에게 모두 보냄
passthroughSubject.send("두번째 값")
}
출력결과
1 번째 sink completion: finished
2 번째 sink completion: finished
func callCurrentValue(){
let currentValueSubject = CurrentValueSubject<String, Never>("첫번째 값")
let sub1 = currentValueSubject
.sink(receiveCompletion: { print("1 번째 sink completion: \($0)") },
receiveValue: { print("1 번째 sink value: \($0)") })
currentValueSubject.send(completion: .finished)
let sub2 = currentValueSubject
.sink(receiveCompletion: { print("2 번째 sink completion: \($0)") },
receiveValue: { print("2 번째 sink value: \($0)") })
// 현재 Subscriber들에게 모두 보냄
currentValueSubject.send("두번째 값")
print(currentValueSubject.value)
}
출력값
1 번째 sink value: 첫번째 값
1 번째 sink completion: finished
2 번째 sink completion: finished
첫번째 값