Swift Academy · Урок

Пользовательские издатели и подписчики

Создавайте собственные компоненты Combine.

Урок 4 из 413 шагов

«Пользовательские издатели и подписчики» — бесплатный урок Swift Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

За пределами встроенных издателей

Фреймворк Combine включает множество издателей, но иногда требуется обернуть программный интерфейс, не использующий Combine, в издатель или обрабатывать значения с точным контролем обратного давления. Для этого необходимо самостоятельно реализовать протоколы издателя и подписчика.

Протокол издателя

Издатель объявляет типы Output и Failure и реализует receive(subscriber:), передавая подписку подключившемуся подписчику.

protocol Publisher {
    associatedtype Output
    associatedtype Failure: Error
    func receive<S: Subscriber>(subscriber: S)
        where S.Input == Output, S.Failure == Failure
}

Роль подписки

Когда подписчик подключается, издатель создаёт объект Subscription. Объект subscription управляет спросом и доставляет значения, связывая издателя с подписчиком. Он соответствует протоколу Subscription, который расширяет Cancellable.

Пользовательская подписка

Объект subscription хранит подписчика и в ответ на запросы спроса выдаёт значения.

final class CountSubscription<S: Subscriber>: Subscription
    where S.Input == Int {
    private var subscriber: S?
    private var current = 0

    init(subscriber: S) {
        self.subscriber = subscriber
    }

    func request(_ demand: Subscribers.Demand) {
        var remaining = demand
        while remaining > 0 {
            remaining -= 1
            remaining += subscriber?.receive(current) ?? .none
            current += 1
        }
    }

    func cancel() {
        subscriber = nil
    }
}

Пользовательский издатель

Издатель просто создаёт подписку и передаёт её подписчику через receive(subscription:).

struct CountPublisher: Publisher {
    typealias Output = Int
    typealias Failure = Never

    func receive<S: Subscriber>(subscriber: S)
        where S.Input == Int, S.Failure == Never {
        let subscription = CountSubscription(subscriber: subscriber)
        subscriber.receive(subscription: subscription)
    }
}

Понимание спроса

Обратное давление — это механизм управления потоком в Combine. Подписчик запрашивает определённый объём Demand, а издатель не должен отправлять больше значений, чем было запрошено. Возврат спроса из receive(_:) увеличивает доступный объём.

Протокол подписчика

Пользовательский подписчик реализует три метода: получает подписку, затем каждое значение и после этого уведомление о завершении.

protocol Subscriber {
    associatedtype Input
    associatedtype Failure: Error
    func receive(subscription: Subscription)
    func receive(_ input: Input) -> Subscribers.Demand
    func receive(completion: Subscribers.Completion<Failure>)
}

Пользовательский подписчик

Здесь подписчик сначала запрашивает два значения, затем запрашивает ещё одно после каждого полученного значения и одновременно выводит их.

final class PrintSubscriber: Subscriber {
    typealias Input = Int
    typealias Failure = Never

    func receive(subscription: Subscription) {
        subscription.request(.max(2))
    }

    func receive(_ input: Int) -> Subscribers.Demand {
        print("Value:", input)
        return .max(1)
    }

    func receive(completion: Subscribers.Completion<Never>) {
        print("Done")
    }
}

Адаптация делегатного интерфейса

Практическое применение пользовательских издателей — адаптация делегатного интерфейса или интерфейса обратных вызовов к Combine, чтобы сделать устаревший код пригодным для композиции. Вы используете store для хранения подписчика и передаёте вызовы делегата как вызовы receive(_:).

Предпочитайте субъекты, когда это возможно

Реализовывать протоколы вручную требуется редко. Для большинства случаев адаптации гораздо проще использовать PassthroughSubject или CurrentValueSubject — достаточно вызвать send(_:).

let subject = PassthroughSubject<Int, Never>()

subject
    .sink { print($0) }
    .store(in: &cancellables)

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

Когда нужна собственная реализация

Выбирайте собственные реализации издателя и подписчика, когда требуется:

  • тонкий контроль обратного давления
  • эффективная адаптация сложного источника, не использующего Combine
  • повторно используемые типобезопасные операторы

В остальных случаях правильным выбором будут субъекты и встроенные операторы.

Быстрая проверка

Проверьте свои знания о пользовательских издателях.

Повторение

Вы научились реализовывать основные протоколы Combine:

  • Издатель создаёт подписку для каждого подписчика
  • Подписка учитывает объём запроса (обратное давление)
  • Подписчик получает подписку, значения и уведомление о завершении
  • Для большинства задач адаптации предпочитайте субъекты

Понимание этих внутренних механизмов помогает разобраться в работе всего Combine.

Можно начать бесплатно

Изучай Swift с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
122
Уроки
409

Часто задаваемые вопросы

Урок «Пользовательские издатели и подписчики» бесплатный?

Да — полный текст урока «Пользовательские издатели и подписчики» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Пользовательские издатели и подписчики»?

Создавайте собственные компоненты Combine. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Пользовательские издатели и подписчики»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Преобразование и объединение потоков
  2. Планировщики и потоки выполнения
  3. Операторы обработки ошибок
  4. Пользовательские издатели и подписчики
← Назад к Swift Academy