swift 4 : How to asynchronously use URLSessionDataTask but have the requests be in a timed queue?

标签 swift multithreading asynchronous networking swift4

基本上,我有一些 JSON 数据,我希望从一堆 URL(全部来自同一主机)中检索这些数据,但是我只能大约每 2 秒请求一次该数据,并且一次只能请求一个数据,否则我将被服务器“时间禁止”。正如您将在下面看到的;虽然 URLSession 非常快,但当我有大约 700 个网址需要访问时,它也会让我几乎立即被禁止。

我将如何在 URLSession 中创建一个队列(如果它的功能支持它)并让它与我的主线程异步工作;它是否在自己的线程上串行工作,并且仅在完成上一个请求后 2 秒后才尝试队列中的每个项目?

for url in urls {
    get(url: url)
}


func get(url: URL) {
    let session = URLSession.shared
    let task = session.dataTask(with: url, completionHandler: { (data, response, error) in

        if let error = error {
            DispatchQueue.main.async {
                print(error.localizedDescription)
            }
            return
        }
        let data = data!

        guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
            DispatchQueue.main.async {
                print("Server Error")
            }
            return
        }
        if response.mimeType == "application/json" {
            do {
                let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
                if json["success"] as! Bool == true {
                    if let count = json["total_count"] as? Int {
                        DispatchQueue.main.async {
                            self.itemsCount.append(count)
                        }
                    }
                }
            } catch {
                print(error.localizedDescription)
            }
        }
    })
    task.resume()
}

最佳答案

递归最好地解决这个问题

import Foundation
import PlaygroundSupport

// Let asynchronous code run
PlaygroundPage.current.needsIndefiniteExecution = true

func fetch(urls: [URL]) {

    guard urls.count > 0 else {
        print("Queue finished")
        return
    }

    var pendingURLs = urls
    let currentUrl = pendingURLs.removeFirst()

    print("\(pendingURLs.count)")

    let session = URLSession.shared
    let task = session.dataTask(with: currentUrl, completionHandler: { (data, response, error) in
        print("task completed")
        if let _ = error {
            print("error received")
            DispatchQueue.main.async {
                fetch(urls: pendingURLs)
            }
            return
        }

        guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
            print("server error received")
            DispatchQueue.main.async {
                fetch(urls: pendingURLs)
            }
            return
        }
        if response.mimeType == "application/json" {
            print("json data parsed")
            DispatchQueue.main.async {
                fetch(urls: pendingURLs)
            }
        }else {
            print("unknown data")
            DispatchQueue.main.async {
                fetch(urls: pendingURLs)
            }
        }
    })

    //start execution after two seconds
    Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
        print("resume called")
        task.resume()
    }
}

var urls = [URL]()
for _ in 0..<100 {
    if let url = URL(string: "https://google.com") {
        urls.append(url)
    }
}

fetch(urls:urls)

关于 swift 4 : How to asynchronously use URLSessionDataTask but have the requests be in a timed queue?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47694633/

相关文章:

python - 将 2 个或更多异步 HTTP 调用的结果设置为命名变量

ios - iOS 系统从 9 - 10 升级后,字体中缺少符号 '$£¥ €'

ios - 将语言从(英语)更改为阿拉伯语时,如何从左到右更改 SWReaveal 侧边菜单形式

c++ - 为什么我们在 Boost.ASIO 中需要很多接受器?

java - 线程在 2 个队列中

c# - 异步和等待混淆

swift - PromiseKit:无法在处理程序之间调用自定义代码

ios - Swift 中的 Facebook iOS SDK v 4.1.0 和 Cocoapods : cannot import modules

java - 同步静态变量

c# - WCF Fire 异步任务(即发即忘风格)- 资源问题