Соблюдать количество операций в очереди URLSession?
я использую
URLSession
настроить таким образом:
public struct NetworkSession {
public var session: URLSession
public let sessionOperationQueue = OperationQueue()
public init() {
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.timeoutIntervalForRequest = 20
sessionOperationQueue.maxConcurrentOperationCount = OperationQueue.defaultMaxConcurrentOperationCount
sessionOperationQueue.qualityOfService = .userInitiated
session = URLSession(configuration: sessionConfiguration, delegate: nil, delegateQueue:sessionOperationQueue)
}
.....
}
Я хотел бы наблюдать за количеством задач, найденных в очереди.
Я попытался использовать Combine:
sessionOperationQueue.publisher(for: \.operationCount).sink { count in
print("operations count: \(count)")
}
.store(in: &subscribers)
Но это только печатает
0
при инициализации и никогда не обновляется по мере запуска и завершения запросов.
Как я могу контролировать количество задач, найденных в очереди?
1 ответ
тл;др
Наблюдение за количеством операций в очереди сеанса не приведет к тому, что вы хотите.
- В традиционном коде очередь используется для отдельных методов делегата, а не для переноса всего запроса-ответа.
- При использовании новой версии очередь операций вообще не используется (что спорно, учитывая предыдущее наблюдение).
В итоге, несмотря на то, что у него есть метод, чтобы узнать, какие ожидающие запросы выполняются, у него, насколько мне известно, нет наблюдаемого свойства для этого (если, конечно, вы не откажетесь от обработчиков завершения и не используете только представления делегата). Итак, если вы хотите динамически отслеживать количество ожидающих запросов, просто следите за этим самостоятельно. Шаблон асинхронного пользовательского подкласса кажется излишним (но он описан в
Длинный ответ с примерами кода
Вы можете использовать KVO для наблюдения за изменениями очереди (см. ниже), но это не приведет к тому, чего вы хотите. Это не операция, обертывающая весь сетевой запрос и ответ, а скорее отдельные операции для отдельных обратных вызовов делегата сеанса и обработчика завершения.
Например, рассмотрим:
class ViewController: UIViewController {
lazy var session: URLSession = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 20
return URLSession(configuration: configuration, delegate: nil, delegateQueue: queue)
}()
let queue: OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
queue.qualityOfService = .userInitiated
return queue
}()
var observer: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
observer = queue.observe(\.operationCount, options: .new) { queue, change in
print("Observer reported operationCount =", change.newValue!)
}
for i in 1000..<1010 {
let url = URL(string: "https://httpbin.org/get?value=\(i)")!
session.dataTask(with: url) { data, _, error in
guard let data = data else {
print(error ?? URLError(.badServerResponse))
return
}
print("Request", i, "returned", data.count, "bytes")
}.resume()
}
}
}
Это производит:
Observer reported operationCount = 1
Observer reported operationCount = 2
Observer reported operationCount = 3
Request 1000 returned 405 bytes
Observer reported operationCount = 4
Observer reported operationCount = 3
Request 1002 returned 405 bytes
Observer reported operationCount = 2
Request 1004 returned 405 bytes
Observer reported operationCount = 1
Request 1001 returned 405 bytes
Observer reported operationCount = 0
Observer reported operationCount = 1
Observer reported operationCount = 2
Request 1006 returned 405 bytes
Observer reported operationCount = 3
Observer reported operationCount = 2
Observer reported operationCount = 3
Request 1005 returned 405 bytes
Observer reported operationCount = 4
Observer reported operationCount = 3
Observer reported operationCount = 4
Request 1003 returned 405 bytes
Observer reported operationCount = 3
Request 1008 returned 405 bytes
Observer reported operationCount = 2
Request 1007 returned 405 bytes
Observer reported operationCount = 1
Request 1009 returned 405 bytes
Observer reported operationCount = 0
Обратите внимание: вы никогда не увидите подтверждение того, что есть десять ожидающих запросов. В
Кстати, в приведенном выше очередь делегатов последовательная (как советовали в документации ). Сам факт того, что это последовательная очередь, позволяющая выполнять одновременные сетевые запросы, является еще одним свидетельством того, что существует не операция, обертывающая весь запрос, а скорее для отдельных обратных вызовов делегата.
Интересно, если вы используете новый
func startRequests() async throws {
try await withThrowingTaskGroup(of: Void.self) { group in
for i in 0..<4 {
let url = URL(string: "https://httpbin.org/get?value=\(i)")!
group.addTask {
let (data, _) = try await self.session.data(from: url)
print("Request", i, "returned", data.count, "bytes")
}
}
try await group.waitForAll()
}
}
Но это спорно, учитывая, что