Оператор combineLatest не выдает, когда внутренние издатели используют подписку(вкл.:)

#ios #swift #combine #combinelatest

Вопрос:

Я наблюдаю неожиданное поведение в отношении combineLatest, если у внутренних издателей есть subscribe(on:) , поток combineLatest не выдает никакого значения.

Примечания:

  • С оператором Zip работает
  • Перемещение подписки(вкл.:) / получения(вкл.:) в поток combineLatest также работает. Но в данном конкретном случае внутренние издатели определяют свою подписку/получение, потому что они (повторно)используются в других местах.
  • Добавление подписки(вкл.:)/получения(вкл.:) только для одного из внутренних издателей также работает, поэтому проблема как раз в том, когда они есть у обоих.
     func makePublisher() -> AnyPublisher<Int, Never> {
        Deferred {
            Future { promise in
                DispatchQueue.global(qos: .background).asyncAfter(deadline: .now()   3) {
                    promise(.success(Int.random(in: 0...3)))
                }
            }
        }
        .subscribe(on: DispatchQueue.global())
        .receive(on: DispatchQueue.main)
        .eraseToAnyPublisher()
    }
    
    var cancellables = Set<AnyCancellable>()
    Publishers.CombineLatest(
        makePublisher(),
        makePublisher()
    )
    .sink { completion in
        print(completion)
    } receiveValue: { (a, b) in
        print(a, b)
    }.store(in: amp;cancellables)
 

Это ошибка объединения или ожидаемое поведение? У вас есть какие-либо идеи о том, как можно настроить такой поток, в котором внутренние пользователи могут определить свой собственный планировщик подписки?

Комментарии:

1. Какой у тебя вопрос?

2. @NewDev только что обновил вопрос

Ответ №1:

Да, это ошибка. Мы можем упростить тестовый случай до этого:

 import Combine
import Dispatch

let pub = Just("x")
    .subscribe(on: DispatchQueue.main)

let ticket = pub.combineLatest(pub)
    .sink(
        receiveCompletion: { print($0) },
        receiveValue: { print($0) })
 

Это никогда ничего не печатает. Но если вы прокомментируете subscribe(on:) оператора, он напечатает то, что ожидается. Если вы оставите subscribe(on:) , но вставите несколько print() операторов, вы увидите, что CombineLatest оператор никогда не отправляет запрос вверх по потоку.

Я предлагаю вам скопировать переопределение CombineX CombineLatest и утилиты , которые ему необходимо скомпилировать (реализации Lock CombineX и LockedAtomic , я думаю). Я тоже не знаю, работает ли версия CombineX, но если она глючит, по крайней мере, у вас есть исходный код и вы можете попытаться его исправить.