Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Archives
Today
Total
관리 메뉴

욤찌의 개발 일기

[Combine] 이제는 더 이상 물러날 곳이 없는 Combine 공부2 - Publisher 본문

TIL

[Combine] 이제는 더 이상 물러날 곳이 없는 Combine 공부2 - Publisher

yyomzzi 2023. 12. 20. 00:17

매일 조금씩이라도 블로그에 기록하자는 것이 목표,,

그래서 오늘은 Combine의 Key Concepts 중 하나인 Publisher를 알아보겠다


💡Publisher

Declares that a type can transmit a sequence of values over time.

⇒ 시간이 흐름에 따라 값의 연속성을 보낼 수 있는 타입

말 그대로 시간이 흐름에 따라 값이 바뀌면 Subscriber의 요청에 따라 바뀐 값을 발행해 주는 역할!!

 

이전 글에서도 언급했던 것 처럼 시간에 따라 값의 연속성을 보낸다는 것이

동작에 따라 값을 한 번에 보내는 것이 아니라 시간의 흐름에 따라 Publisher가 값을 방출한다고 함. 

시간이 흐름에 따라 방출된 값이 Subscriber로 전달됨

 

A publisher delivers elements to one or more Subscriber instances. The subscriber’s Input and Failure associated types must match the Output and Failure types declared by the publisher. The publisher implements the receive(subscriber:) method to accept a subscriber.

⇒ 하나 이상의 Subscriber 인스턴스에게 요소를 전달함. subscriber의 Input과 Failure 연관값은 publisher의 Output과 Failure 타입과 일치해야 함. publisher는 subscriber를 받기 위해 receive(subscriber:) 함수를 구현함. 

 

여기서 associated types, 연관값이라고 언급했는데

바로 Publisher가 프로토콜로 정의되어 있기 때문에 Generic을 사용할 수가 없어서 

프로토콜에서 Generic과 같은 역할을 하는 associatedtype으로 타입을 지정해줌!

 

그래서 Publisher의 선언은 다음과 같다

 

Publisher는 2개의 연관값과 한 개의 함수로 구현되어 있고 extension으로 코드가 확장되어 있다. 

 

1. Output : Publisher가 방출하는 값.

 

2. Failure : Publisher가 방출하는 에러값.

    만약 publisher가 에러를 방출하지 않는다면 (에러가 발생하지 않는다면!) Never 타입을 사용하면 됨.

 

3. receive(subscriber: ) : Publisher와 Subscriber를 연결해 주는 함수.

함수 파라미터 subscriber에 해당 publisher를 구독해서 값을 받아올 subscriber를 넣어주면 됨.

함수 정의에서도 알 수 있듯이 publisher의 Output과 subscriber의 Input 타입이 같아야 하고,

서로의 Failure 타입도 같아야 한다. 역시 강타입언어,,

 

근데 공식문서에 publisher 함수가 receive 말고도 subscribe(_:) 함수도 있음.

subscribe함수는 receive 함수와 하는 일은 유사해 보이는데 공식문서에서는 이렇게 말한다.

 

Always call this function instead of receive(subscriber:). Adopters of Publisher must implement receive(subscriber:). The implementation of subscribe(_:) provided by Publisher calls through to receive(subscriber:).

receive 함수 대신에 subscribe 함수를 호출하라고 함.

subscribe 내부에 필수 구현자인 receive 함수가 구현되어 있다고 함.

그래서 subscribe를 권장하니까 이거 쓰면 될 듯!


💡Creating Your Own Publishers

Publisher는 프로토콜로 되어있기 때문에 개발자가 직접 구현할 수 있기는 하지만 애플에서 권장하지는 않는다고 함. 

그래서 애플에서 권장하는 방법은 직접 구현보다는 Combine Framework가 제공하는 여러 타입들을 사용해서 

자체적은 Publisher를 생성하는 것이다.

그 방법은 3가지로 아래와 같다.

 

1. PassthroughSubject 같이 Subject의 서브클래스를 사용해서 send(_:) 메서드 호출로 요청된 값 발행하기

2. CurrentValueSubject를 이용해서 subject의 값이 변경될 때마다 값을 방출

3. @Published 어노테이션 사용하기

 

이건 나중에 Subject를 보면서 다시 보도록 하겠숨.

 


💡Convenience Publishers

애플에서 Publisher를 직접 구현하는 것을 권장하지 않는다면 역싀나 미리 만들어놨겠쥬?애플에서 미리 만들어놓은 Publisher들을 알아보자!

1. Just

: A publisher that emits an output to each subscriber just once, and then finishes.

Subscriber에게 한 번만 값을 내보낸 후에 종료하는 가장 간단한 Publisher.

Just는 Failure 타입이 Never이기 때문에 에러를 방출하지 않는다. 항상 값을 생성한다고 보면 됨. 

Failure가 Never 타입으로 정의되어있음

let justPublisher = Just(5)

justPublisher.sink { completion in
    print("Completion: \(completion)")
} receiveValue: { value in
    print("Value: \(value)")
}

// Value: 5
// Completion: finished

 

5라는 값을 방출하는 Just로 Publisher를 정의한 후에 

sink로 publisher가 보내주는 값을 받아서 처리함!

(여기서 sink는 Subscriber의 한 종류로 subscriber 공부할 때 보겠음!!)

 

2. Future

: A publisher that eventually produces a single value and then finishes or fails.

하나의 값을 생성한 다음 완료하거나 실패하는 publisher.

Future의 클로저는 (Result <Output, Failure>) → Void 타입의 클로저인 Future.Promise를 매개변수로 받음.

다른 Publisher들은 모두 struct인데 Future만 Class로 구현되어 있음.

(이렇다 할 이유는 찾지 못했는데 ,, 아무래도 뭔가 참조타입으로 사용해야 할 목적이 있나 봄,,)

func generateAsyncRandomNumberFromFuture() -> Future <Int, Never> {
    return Future() { promise in
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            let number = Int.random(in: 1...10)
            promise(Result.success(number))
        }
    }
}


let cancellable = generateAsyncRandomNumberFromFuture()
    .sink { number in print("Got random number \(number).") }

Future는 특히 비동기 작업을 수행할 때 쓰인다고 함. 

공식문서에 있는 예시를 가져와봤음. 

Int값을 Output으로 같고 에러는 발생시키지 않는 Future publisher를 리턴하는 함수를 정의함. 

Future 클로저의 Promise의 Output으로 1~10까지의 숫자 중 랜덤으로 값을 하나 방출하게 되고 클로저가 실행되고 2초 뒤에 값을 받을 수 있음.

그래서 sink로 값을 받게 되면 2초뒤에 랜덤 숫자가 프린트되는 것을 볼 수 있음!

 

3. Deferred

: A publisher that awaits subscription before running the supplied closure to create a publisher for the new subscriber.

신규 subscriber를 위한 publisher를 생성하기 위해 제공하는 클로저를 실행하기 전에 subscription을 기다리는 publisher. Deferred 자체가 “지연된” 뜻이기 때문에 찾아보니까 lazy랑 비슷한 개념이라는 글도 봤었음. 

lazy와 비슷하게 Publisher가 실제로 사용될 때 publisher를 생성하기 때문에 메모리를 더 효율적으로 쓸 수 있다고 함.

 

4. Empty

: A publisher that never publishes any values, and optionally finishes immediately.

어떠한 값도 방출하지 않고 바로 completion 이벤트를 방출할지 선택할 수 있는 publisher.

아무 값도 내보내지 않아서 Empty라는 이름으로 쓰이는 ,,것 같음

 

5. Fail

: A publisher that immediately terminates with the specified error.즉시 에러를 방출하면서 종료시키는 publisher.

 

6. Record

: A publisher that allows for recording a series of inputs and a completion, for later playback to each subscriber.나중에 subscriber에게 전달하기 위해 input과 completion을 미리 record 해두는 publisher.

 

각 Publisher의 예시와 특이점은 좀 더 공부해 본 후에 추가하도록 하겠당


 

📖 reference(늘 감사합니당) ♥️

https://developer.apple.com/documentation/combine/publisher

 

Publisher | Apple Developer Documentation

Declares that a type can transmit a sequence of values over time.

developer.apple.com

https://icksw.tistory.com/273

 

[Combine] 미리 정의된 Publisher들 - Combine 공부 3

안녕하세요 Pingu입니다.🐧 지난 글에서는 Publisher, Subscriber 프로토콜 그 자체에 대해 알아봤었는데요, 이번 글에서는 Publisher 프로토콜로 Apple에서 미리 구현한 Publisher들을 알아보려고 합니다. 간

icksw.tistory.com

https://sujinnaljin.medium.com/combine-publisher-5add887b97f3

 

[Combine] Publisher

발행🏭

sujinnaljin.medium.com

https://dongminyoon.tistory.com/79

 

[Combine] Publisher

이전에는 Combine이 무엇인지 어떤 목적을 위해 만들어졋는지에 대해 간단히 알아보았습니다. 이번에는 그 중에서 Publisher라는 것에 대해서 알아보려고 합니다 🙃 Publisher란? 이전 맛보기 글에서

dongminyoon.tistory.com

 

'TIL' 카테고리의 다른 글

[Combine] 이제는 더 이상 물러날 곳이 없는 Combine 공부1  (0) 2023.12.18