У меня есть протокол, определенный следующим образом:
protocol Prompter {
func promptIfNeeded() async -> Bool
}
И массив Prompter соответствующих типов:
var prompters: [Prompter] { [PrompterA(), PrompterB()] }
В настоящее время я перебираю этот массив, запрашивая каждое сообщение пользователю одно за другим, используя asyncawait:
for prompter in prompters {
let result = await prompter.promptIfNeeded()
print("The result is \(result)")
}
Однако мне интересно использовать Combine издателей вместо asyncawait. Любые указания по этому поводу?
Примечание. Каждое приглашение должно дождаться завершения предыдущего.
@Sweeper Я хочу удалить все async/await и использовать Future. Спасибо!





Если вы хотите, чтобы они выполнялись последовательно, вы можете использовать Publishers.Sequence с FlatMap с Subscribers.Demand из .max(1) . Очевидно, что метод должен будет возвращать Future. Итак, возможно:
protocol Prompter {
func promptIfNeeded() -> Future<Bool, Never>
}
struct PrompterA: Prompter {
func promptIfNeeded() -> Future<Bool, Never> {
Future { promise in
…
promise(.success(result)) // where `result` is some `Bool`
}
}
}
struct PrompterB: Prompter { … }
class Foo {
var cancellables: Set<AnyCancellable> = []
func performPrompts() {
let prompters: [Prompter] = [PrompterA(), PrompterB()]
Publishers.Sequence(sequence: prompters)
.flatMap(maxPublishers: .max(1)) { $0.promptIfNeeded() }
.sink { print($0) }
.store(in: &cancellables)
}
}
Существуют и другие вариации на эту тему, но, надеюсь, это иллюстрирует идею: в «Комбайне» можно использовать flatMap с maxPublishers из .max(1)) для последовательного поведения.
ИМХО, я считаю, что код async-await значительно улучшает приведенный выше код, но я хотел ответить на ваш вопрос, и вы можете решить, что вы предпочитаете.
Спасибо! Почему здесь вы предпочитаете async/awaitCombine?
Я считаю, что цикл for гораздо более интуитивен, чем описанный выше. Использование async-await приводит к меньшему синтаксическому шуму (нет необходимости в приемниках, отменяемых значениях, фьючерсах и т. д.), имеет приятный линейный поток вместо того, чтобы полагаться на замыкания, удалять типы, подобные Result, и т. д. Комбайн был лучшей вещью, когда он был был представлен в 2019 году, но когда в 2021 году была представлена параллельная обработка Swift, это несколько снизило полезность Joint. Немного необычно видеть, как кто-то просит провести рефакторинг кода параллелизма Swift в соответствии со старыми шаблонами объединения. Но, повторюсь, вы вольны использовать все, что захотите.
Эй, если вы используете кодовую базу с большим количеством комбинаций и хотите, чтобы все использовало этот шаблон, тогда это здорово. Комбайн имеет более декларативную атмосферу, что делает его удобным в использовании и в кодовой базе SwiftUI. Но если у вас есть кодовая база async-await, я бы не был склонен просто реорганизовать ее для объединения без достаточно убедительных аргументов.
Как вы хотите «задействовать» издателей? Хотите удалить все
async/awaitиз своего кода? то есть вместо этого изменитьpromptIfNeededна возвратFuture? Или вы хотите обернуть текущийpromptIfNeededиздателем и заменить цикл for операторами объединения? Или оставить все асинхронные элементы, но использовать последовательностьBoolкакAnyPublisher<Bool, Never>?