В основном вам нужно завернуть полученного подписчика во что-то. Вы можете написать свою собственную абстракцию над этим, однако Combine уже предоставляет необходимые инструменты для этого: AnySubscriber (тип ластика, который вы упомянули).
public struct AudioVolumePublisher: Publisher {
public typealias Output = AudioVolume
public typealias Failure = Error
private var subscriptions = [AudioVolumeSubscription]()
func receive<S>(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input {
// some cleanup first, to remove disconnected subscribers
subscribers = subscribers.filter { $0.subscriber != nil }
// register the subscriber
subscribers.append(AudioVolumeSubscription(subscriber))
// signal availability to the subscriber
subscriber.receive(subscription)
}
Обратите внимание, что в этой реализации AudioVolumeSubscription
не является универсальным c, это не обязательно должно быть:
public class AudioVolumeSubscription: NSObject, Subscription {
// also note the weak reference, we don't want to keep the subscriber alive more
// than needed, and this also avoids possible retain cycles
private weak var subscriber: AnySubscriber<AudioVolume, Error>?
// the generic responsibility was moved on the shoulders of the initializer
public init<S: Subscriber>(for subscriber: S) where S.Input == AudioVolume, S.Failure == Error {
self.subscriber = AnySubscriber(subscriber)
}
Также обратите внимание, что это упрощенная c реализация, когда издатель сразу же сообщает о доступности. Не все издатели делают это, однако в вашем случае, похоже, это так.