Swift Combine: Создаст ли multicast(_:) новый объект для каждого подписчика

Вопрос или проблема

В этом коде почему debug: multicast triggered.. выводится только один раз, хотя есть 2 подписчика. Поскольку Apple утверждает, что multicast(_:) создает нового издателя для каждого подписчика, разве это не должно привести к тому, что оператор print будет вызван дважды?

import Foundation
import Combine

var cancellables = Set<AnyCancellable>()
let upstreamPublisher = Range(1...3).publisher.delay(for: 1, scheduler: DispatchQueue.main)

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

// Создаем мультикаст-издателя и применяем автосоединение
let multicastPublisher = upstreamPublisher
    .multicast({
        print("debug: multicast triggered..")
        return sharedSubject
    })
    .autoconnect()

// Подписчик 1
multicastPublisher
    .sink { value in
        print("Подписчик 1 получил значение: \(value)")
    }
    .store(in: &cancellables)

// Подписчик 2
multicastPublisher
    .sink { value in
        print("Подписчик 2 получил значение: \(value)")
    }
    .store(in: &cancellables)

// Вывод
//debug: multicast triggered..
//Подписчик 1 получил значение: -1
//Подписчик 2 получил значение: -1
//Подписчик 1 получил значение: 1
//Подписчик 2 получил значение: 1
//Подписчик 1 получил значение: 2
//Подписчик 2 получил значение: 2
//Подписчик 1 получил значение: 3
//Подписчик 2 получил значение: 3

Ответ или решение

Основной вопрос заключается в том, почему сообщение «debug: multicast triggered..» выводится только один раз, несмотря на то что есть два подписчика. Для понимания этого поведения необходимо рассмотреть, как работает оператор multicast(_:) в Swift Combine и что он действительно делает.

Когда вы используете multicast(_:), он создает «мультикастированный» дельта-издатель, который предоставляет возможность нескольким подписчикам получать одно и то же значение или события от базового источника (в данном случае upstreamPublisher). Однако ключевой момент заключается в том, что multicast не создает новый издатель для каждого подписчика, а вместо этого предоставляет один и тот же экземпляр Publisher, который делит свою работу между всеми подписчиками.

При вызове метода multicast(_:), код внутри замыкания (…) будет выполнен только один раз при первом подключении к multicastPublisher. Это означает, что ваш вызов print("debug: multicast triggered..") выполняется один раз при создании экземпляра sharedSubject, который затем используется всеми подписчиками. Таким образом, именно поэтому вы видите сообщение только один раз.

Также стоит обратить внимание на оператор autoconnect(). Он автоматически подключает многократных подписчиков к источнику событий немедленно, всего лишь один раз.

В вашем коде:

  1. Вы создаете rangePublisher, который генерирует значения от 1 до 3 с задержкой в 1 секунду.
  2. Создается с помощью CurrentValueSubject общий издатель sharedSubject, из которого будет получено значение -1 для подписчиков до того, как будет произведена первая публикация из upstreamPublisher.
  3. Вызов multicast создаёт единственный экземпляр sharedSubject, который будет использован всеми подписчиками.

В результате два подписчика получают одно и то же значение -1, а затем все подписчики начинают получать значения от upstreamPublisher. Поскольку multicast не создает новый издатель каждый раз для каждого подпистчика, вызов внутри multicast срабатывает лишь единожды.

Таким образом, выводимое сообщение «debug: multicast triggered..» действительно соответствует тому, как работает multicast, и выводится только один раз, подтверждая, что все подписчики используют один и тот же общий экземпляр издателя.

Оцените материал
Добавить комментарий

Капча загружается...