基本上,我有一些 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/