Я открываю для себя Combine. Я написал методы, которые «комбинируют» HTTP-запросы, например:
func testRawDataTaskPublisher(for url: URL) -> AnyPublisher<Data, Error> {
var request = URLRequest(url: url,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 15)
request.httpMethod = "GET"
return urlSession.dataTaskPublisher(for: request)
.tryMap {
return $0.data
}
.eraseToAnyPublisher()
}
Я бы хотел вызвать метод несколько раз и все-таки выполнить задачу, например:
let myURLs: [URL] = ...
for url in myURLs {
let cancellable = testRawDataTaskPublisher(for: url)
.sink(receiveCompletion: { _ in }) { data in
// save the data...
}
}
Приведенный выше код не будет работать, потому что мне нужно сохранить отменяемое значение в переменной, принадлежащей классу. Первый вопрос: это хорошая идея хранить много (например, 1000) отменяемых файлов в чем-то вроде _3 _ ??? Не вызовет ли это утечки памяти?
var cancellables = Set<AnyCancellable>()
...
let cancellable = ...
cancellables.insert(cancellable) // ???
И второй вопрос: как запустить задачу, когда все отменяемые завершены? Я думал о чем-то подобном
class Test {
var cancellables = Set<AnyCancellable>()
func run() {
// show a loader
let cancellable = runDownloads()
.receive(on: RunLoop.main)
.sink(receiveCompletion: { _ in }) { _ in
// hide the loader
}
cancellables.insert(cancellable)
}
func runDownloads() -> AnyPublisher<Bool, Error> {
let myURLs: [URL] = ...
return Future<Bool, Error> { promise in
let numberOfURLs = myURLS.count
var numberOfFinishedTasks = 0
for url in myURLs {
let cancellable = testRawDataTaskPublisher(for: url)
.sink(receiveCompletion: { _ in }) { data in
// save the data...
numberOfFinishedTasks += 1
if numberOfFinishedTasks >= numberOfURLs {
promise(.success(true))
}
}
cancellables.insert(cancellable)
}
}.eraseToAnyPublisher()
}
func testRawDataTaskPublisher(for url: URL) -> AnyPublisher<Data, Error> {
...
}
}
Обычно я бы использовал DispatchGroup
, запускал несколько задач HTTP и получал уведомление, когда задачи завершены, но мне интересно, как написать это современным способом, используя Combine.