banner

서론

해당 포스트는 CombineSubject 에 대해 정리한 내용입니다.

Subjects

SubjectPublisher 이자 Subscriber 입니다. SubjectPublisher 로서 데이터를 발행할 수 있고, Subscriber 로서 데이터를 받을 수 있습니다.

Subject 는 다음과 같은 종류가 있습니다.

PassthroughSubject

PassthroughSubject 는 가장 일반적인 Subject 입니다. PassthroughSubject 는 데이터를 받으면 그대로 다시 발행합니다. 그리고 초기값을 가질 수 없습니다. 그리고 구독을 한 시점 이후에 발행된 데이터만 받을 수 있습니다.

import Combine

let subject = PassthroughSubject<Int, Never>()

subject.send(1) // nothing happens

let cancellable = subject.sink { value in
    print("Received value: \(value)")
}

subject.send(2) // 0
subject.send(3) //1

CurrentValueSubject

CurrentValueSubject 는 초기값을 가질 수 있는 Subject 입니다. CurrentValueSubject 는 가장 최근의 값을 저장하고, 새로운 Subscriber 가 구독을 시작하면 가장 최근의 값을 전달합니다.

let subject = CurrentValueSubject<Int, Never>(-1)

subject.send(0)

let subscription = subject.sink { value in  // 구독을 시작 한 시점에 가장 최근 값인 0을 받는다.
    print("Received value: \(value)")
}

subject.send(1)
subject.send(2)

Custom Subject

Subject 를 상속받아서 커스텀 Subject 를 만들 수 있습니다.

아래 코드는 짝수만 발행하는 EvenNumberSubject 를 만드는 예제입니다.

class EvenSubject<Failure: Error>: Subject {
    typealias Output = Int

    private let wrapped: CurrentValueSubject<Int, Failure>

    init(initialValue: Int) {
        let evenInitialValue = initialValue % 2 == 0 ? initialValue : 0

        wrapped = CurrentValueSubject(evenInitialValue)
    }

    func send(_ value: Int) {
        if value % 2 == 0 {
            wrapped.send(value)
        }
    }

    func send(completion: Subscribers.Completion<Failure>) {
        wrapped.send(completion: completion)
    }

    func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Int == S.Input {
        wrapped.receive(subscriber: subscriber)
    }

    func send(subscription: Subscription) {
        wrapped.send(subscription: subscription)
    }
}

let evenSubject = EvenSubject<Never>(initialValue: 2)
let cancellable = evenSubject.sink { value in.  // 최초 구독하자마자 2를 수신
    print("Received value: \(value)")
}


 evenSubject.send(3) // 3은 짝수가 아니므로 무시
 evenSubject.send(4)  // 4를 수신
 evenSubject.send(5)  // 5는 짝수가 아니므로 무시

댓글남기기