구독자에게 element를 전달하는 역할, RxSwift의 Observable
protocol Publisher<Output, Failure>
let publisher = Publisher<Int, Never>()
Output
은 Publisher
가 값을 방출하는 타입이며, Failure
는 publisher
가 방출할 수 있는 에러의 종류
associatedtype Failure: Error
Never인 경우 에러가 발생할 일이 없다는 것을 의미한다.
값을 하나만 가지는 Publisher. RxSwift의 Just와 동일한 개념
let just = Just("This is Output")
just.sink(receiveCompletion: { completion in
print("received completion: \(completion)")
},
receiveValue: { value in
print("received value: \(value)")
}
// received value: This is Output
// received completion: finished
Just와 마찬가지로 값을 하나만 방출. 결과를 비동기로 처리
let future = Future<Int, Never> { promise in
promise(.success(1))
}
future.sink {
print($0)
} receiveValue: {
print($0)
}
.store(in: &subscriptions)
// 1
// finished
RxSwift의 Single과 비슷해보인다.
Single은 success, fail만 전달하는데 Sink는 종료까지 이벤트를 받는다는 점에서 다르다.
네트워크 통신할 때 Single타입으로 반환했는데 Combine에서도 동일할까? 직접 경험해봐야 알겠다..
직역하자면 지연된..이라는 의미이다. 뭔소린지 이해를 못하겠다.
정의를 할 때 클로저를 통해 처리할 것들은 먼저 하고 가장 마지막에 Publisher를 반환하면서 정의하는 것 같다.
구독하기 전에 반드시 처리해야할 일들이 있을 때 클로저로 처리해줘야할 때 사용해야할듯..
example(of: "deferred") {
struct DoyunPublisher: Publisher {
typealias Output = String
typealias Failure = Never
func receive<S>(subscriber: S) where S : Subscriber, Never == S.Failure, String == S.Input {
subscriber.receive("1")
subscriber.receive(completion: .finished)
}
}
print(3)
let deferred = Deferred {
print(2)
return DoyunPublisher()
}
deferred.sink {
print($0)
} receiveValue: {
print($0)
}
}
// 3
// 2
// 1
// finished
어떠한 값을 넣어도 아무런 Output을 반환하지 않는다. completion여부만 반환해주게 된다.
example(of: "empty") {
let empty = Empty<String, Never>()
empty.sink {
print($0)
} receiveValue: {
print($0)
}
}
// finished
Empty와 비슷하게 Output을 반환하지 않고 Error만 반환하는 형태이다.
example(of: "fail") {
enum FailError: Error {
case custom
}
let fail = Fail<String, FailError>(error: .custom)
fail.sink {
print("Error: \($0)")
} receiveValue: {
print($0)
}
}
정의를 직역하면 각각의 subscriber에게 나중에 input와 completion을 playback해주기 위해 inputs와 completion을 저장하는 publisher라고 한다.
_ = Record(
output: Array(1...3),
completion: .failure(SomeError.test)
)
.scan(0) { $0 + $1 }
.sink(
receiveCompletion: { print($0) },
receiveValue: { print($0) }
)
Just는 Failure타입이 Never이다. 하지만 completion될 때 .finished가 아닌 특정 completion으로 나타내기 위해 정의할 때 쓰이는 것 같다.
다른 래핑된 Publisher의 타입을 지워주고 Publisher형태로 반환되는 것 같다.
예를 들어 Publisher에 값을 주입할 수 있는 PassthroughSubject에서 더이상 send 메소드를 사용하지 않고 subscribe만 하는게 확정적이라면 eraseToAnyPublisher()을 사용하여 AnyPublisher로 만들어주면 된다.
example(of: "AnyPublisher") {
let originPublisher = PassthroughSubject<Int, Never>()
originPublisher.send(1)
originPublisher.send(2)
let anyPublisher = originPublisher.eraseToAnyPublisher()
anyPublisher.sink {
print($0)
} receiveValue: {
print($0)
}
}