[Combine] Publisher

도윤·2022년 12월 27일
0

Publisher

구독자에게 element를 전달하는 역할, RxSwift의 Observable

protocol Publisher<Output, Failure>

let publisher = Publisher<Int, Never>()

OutputPublisher 가 값을 방출하는 타입이며, Failurepublisher가 방출할 수 있는 에러의 종류

associatedtype Failure: Error

Never인 경우 에러가 발생할 일이 없다는 것을 의미한다.

미리 정의된 Publisher

  • Just(Struct)

값을 하나만 가지는 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
  • Future(Class)

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에서도 동일할까? 직접 경험해봐야 알겠다..

  • Deffered(Struct)

직역하자면 지연된..이라는 의미이다. 뭔소린지 이해를 못하겠다.

정의를 할 때 클로저를 통해 처리할 것들은 먼저 하고 가장 마지막에 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
  • Empty(struct)

어떠한 값을 넣어도 아무런 Output을 반환하지 않는다. completion여부만 반환해주게 된다.

example(of: "empty") {
    let empty = Empty<String, Never>()
    
    empty.sink {
        print($0)
    } receiveValue: {
        print($0)
    }
}
// finished
  • Fail(struct)

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)
    }
}
  • Record(struct)

정의를 직역하면 각각의 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으로 나타내기 위해 정의할 때 쓰이는 것 같다.

  • AnyPublisher

다른 래핑된 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)
    }
}

https://icksw.tistory.com/273

https://www.vadimbulavin.com/asynchronous-programming-with-future-and-promise-in-swift-with-combine-framework/

https://scotteg.github.io/using-record

0개의 댓글