gpt4 book ai didi

swift - 如何使用 Swift 3 GCD 处理许多 API 调用

转载 作者:行者123 更新时间:2023-11-28 08:23:51 25 4
gpt4 key购买 nike

我正在构建一个 Swift 应用程序以与 MDM API 交互以通过 PUT 命令进行大量更新,但我遇到了如何在不使服务器过载的情况下处理大量 API 调用的问题。

我正在通过 CSV 进行解析,每一行都是一个更新。如果我异步运行命令,它会立即生成并发送所有 API 调用,这是服务器不喜欢的。

但如果我同步运行命令,它会卡住我的 GUI,这不太理想,因为最终用户不知道发生了什么,还剩多长时间,如果出现故障等等。

我也尝试过创建自己的 NSOperation 队列并将最大项目数设置为 5,然后将同步函数放在那里,但这似乎也不是很好。它仍然会通过一些真正随机的 UI 更新来卡住 GUI,这些更新充其量看起来是错误的。

服务器一次可以处理 5-10 个请求,但这些 CSV 文件有时可能超过 5,000 行。

那么,如何限制循环中同时发出的 PUT 请求的数量,同时又不让 GUI 卡住?老实说,我什至不关心最终用户是否可以在运行时与 GUI 进行交互,我只是希望能够就目前运行的线路提供反馈。


我有一个同事写的大部分包装器,异步函数如下所示:

func sendRequest(endpoint: String, method: HTTPMethod, base64credentials: String, dataType: DataType, body: Data?, queue: DispatchQueue, handler: @escaping (Response)->Swift.Void) {
let url = self.resourceURL.appendingPathComponent(endpoint)
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30.0)
request.httpMethod = "\(method)"

var headers = ["Authorization": "Basic \(base64credentials)"]
switch dataType {
case .json:
headers["Content-Type"] = "application/json"
headers["Accept"] = "application/json"
if let obj = body {
do {
request.httpBody = try JSONSerialization.data(withJSONObject: obj, options: JSONSerialization.WritingOptions(rawValue: 0))
} catch {
queue.async {
handler(.badRequest)
}
return
}
}
case .xml:
headers["Content-Type"] = "application/xml"
headers["Accept"] = "application/xml"
request.httpBody = body
/*if let obj = body {
request.httpBody = (obj as! XMLDocument).xmlData
}*/
}
request.allHTTPHeaderFields = headers

session.dataTask(with: request) {
var response: Response
if let error = $2 {
response = .error(error)
} else {
let httpResponse = $1 as! HTTPURLResponse
switch httpResponse.statusCode {
case 200..<299:
if let object = try? JSONSerialization.jsonObject(with: $0!, options: JSONSerialization.ReadingOptions(rawValue: 0)) {
response = .json(object)
} else if let object = try? XMLDocument(data: $0!, options: 0) {
response = .xml(object)
} else {
response = .success
}
default:
response = .httpCode(httpResponse.statusCode)
}
}

queue.async {
handler(response)
}
}.resume()

然后,有一个使用信号量的同步选项,如下所示:

    func sendRequestAndWait(endpoint: String, method: HTTPMethod, base64credentials: String, dataType: DataType, body: Data?) -> Response {
var response: Response!
let semephore = DispatchSemaphore(value: 0)
sendRequest(endpoint: endpoint, method: method, base64credentials: base64credentials, dataType: dataType, body: body, queue: DispatchQueue.global(qos: .default)) {
response = $0
semephore.signal()
}
semephore.wait()
return response
}

使用信息如下:

class ViewController: NSViewController {

let client = JSSClient(urlString: "https://my.mdm.server:8443/", allowUntrusted: true)
let credentials = JSSClient.Credentials(username: "admin", password: "ObviouslyNotReal")


func asynchronousRequestExample() {
print("Sending asynchronous request")

client.sendRequest(endpoint: "computers", method: .get, credentials: credentials, dataType: .xml, body: nil, queue: DispatchQueue.main) { (response) in

print("Response recieved")

switch response {
case .badRequest:
print("Bad request")
case .error(let error):
print("Receieved error:\n\(error)")
case .httpCode(let code):
print("Request failed with http status code \(code)")
case .json(let json):
print("Received JSON response:\n\(json)")
case .success:
print("Success with empty response")
case .xml(let xml):
print("Received XML response:\n\(xml.xmlString(withOptions: Int(XMLNode.Options.nodePrettyPrint.rawValue)))")
}

print("Completed")
}

print("Request sent")

}

func synchronousRequestExample() {
print("Sending synchronous request")

let response = client.sendRequestAndWait(endpoint: "computers", method: .get,credentials: credentials, dataType: .json, body: nil)

print("Response recieved")

switch response {
case .badRequest:
print("Bad request")
case .error(let error):
print("Receieved error:\n\(error)")
case .httpCode(let code):
print("Request failed with http status code \(code)")
case .json(let json):
print("Received JSON response:\n\(json)")
case .success:
print("Success with empty response")
case .xml(let xml):
print("Received XML response:\n\(xml.xmlString(withOptions: Int(XMLNode.Options.nodePrettyPrint.rawValue)))")
}

print("Completed")
}


override func viewDidAppear() {
super.viewDidAppear()
synchronousRequestExample()
asynchronousRequestExample()

}

我稍微修改了发送函数,这样它们就可以直接使用 base64 编码的凭据,也许还有一两个其他的东西。

最佳答案

您不能只将操作链接起来,以便每个操作一次发送 3/4 的请求吗?

https://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift

如您所知,NSOperation(也由 Operation with Swift3 抽象)默认在后台线程上运行。请注意不要在可能会在主线程上运行任务的完成 block 中运行繁重的任务(这会卡住您的 UI)。

我看到的唯一可以卡住您的 UI 的其他情况是一次执行太多操作。

关于swift - 如何使用 Swift 3 GCD 处理许多 API 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40624570/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com