UI обновляется не на главном потоке — что чинит: receive(on:) или subscribe(on:)? Объясните, что переносит каждый.
Этот publisher декодирует на фоновой очереди и обновляет label, но UI иногда меняется не на главном потоке и срабатывает проверка главного потока.
URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: Model.self, decoder: JSONDecoder())
.subscribe(on: DispatchQueue.global())
.sink(receiveCompletion: { _ in }) { model in
self.label.text = model.title // выполняется не на главном потоке
}
.store(in: &cancellables)
Решите, что чинит — receive(on:) или subscribe(on:), поставьте его правильно и скажите, что переносит каждый оператор.
Нужен receive(on: DispatchQueue.main) прямо перед sink. receive(on:) переносит значения, завершение и подписчика ниже него на этот scheduler. subscribe(on:) задаёт лишь, где стартует подписка и восходящая работа, поэтому доставку в UI он не чинит.
- ✗Думают, что
subscribe(on:)управляет тем, где доставляются значения - ✗Ставят
receive(on:)выше по цепочке, а не прямо передsink - ✗Считают, что
sinkпо умолчанию запускает замыкание значения на главном потоке
- →Что будет, если вызвать
receive(on:)дважды в разных местах? - →Почему
subscribe(on:)не влияет на поток подписчика?
subscribe(on:) only controls where the subscription and upstream work start; it does not affect which thread the subscriber runs on. Insert receive(on: DispatchQueue.main) just before sink:
URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: Model.self, decoder: JSONDecoder())
.subscribe(on: DispatchQueue.global()) // decode off-main (optional)
.receive(on: DispatchQueue.main) // deliver on main
.sink(receiveCompletion: { _ in }) { model in
self.label.text = model.title
}
.store(in: &cancellables)
receive(on:) moves everything downstream of it (values, completion, the sink) onto its scheduler; subscribe(on:) moves only the subscription and upstream start, so it cannot fix a main-thread UI update.