swift - Swift 中的异步线程 - 如何处理?
问题描述
我正在尝试从 URL 中恢复数据集(在通过parseJSON函数解析 JSON 后,该函数正常工作 - 我没有将它附加到下面的代码段中)。
结果返回nil - 我相信这是因为retrieveData函数中的闭包是异步处理的。我无法将结果保存到targetData中。
在此先感谢您的帮助。
class MyClass {
var targetData:Download?
func triggerEvaluation() {
retrieveData(url: "myurl.com") { downloadedData in
self.targetData = downloadedData
}
print(targetData) // <---- Here is where I get "nil"!
}
func retrieveData(url: String, completion: @escaping (Download) -> ()) {
let myURL = URL(url)!
let mySession = URLSession(configuration: .default)
let task = mySession.dataTask(with: myURL) { [self] (data, response, error) in
if error == nil {
if let fetchedData = data {
let safeData = parseJSON(data: fetchedData)
completion(safeData)
}
} else {
//
}
}
task.resume()
}
}
解决方案
是的,这是nil
因为异步运行,即在您点击语句retrieveData
时尚未检索到数据。print
将print
语句(可能还有 UI 的所有更新)移动到闭包中,就在您设置的位置self.targetData
)。
例如
func retrieveData(from urlString: String, completion: @escaping (Result<Download, Error>) -> Void) {
let url = URL(urlString)!
let mySession = URLSession.shared
let task = mySession.dataTask(with: url) { [self] data, response, error in
guard
let responseData = data,
error == nil,
let httpResponse = response as? HTTPURLResponse,
200 ..< 300 ~= httpResponse.statusCode
else {
DispatchQueue.main.async {
completion(.failure(error ?? NetworkError.unknown(response, data))
}
return
}
let safeData = parseJSON(data: responseData)
DispatchQueue.main.async {
completion(.success(safeData))
}
}
task.resume()
}
在哪里
enum NetworkError: Error {
case unknown(URLResponse?, Data?)
}
然后调用者会:
func triggerEvaluation() {
retrieveData(from: "https://myurl.com") { result in
switch result {
case .failure(let error):
print(error)
// handle error here
case .success(let download):
self.targetData = download
// update the UI here
print(download)
}
}
// but not here
}
一些不相关的观察:
您不想
URLSession
为每个请求创建一个新的。只创建一个并将其用于所有请求,或者shared
像我上面那样使用。确保每条执行路径都
retrieveData
调用闭包。它可能还不是很关键,但是当我们编写异步代码时,我们总是希望确保我们调用了闭包。为了检测错误,我建议使用
Result
上面显示的模式,它在哪里.success
或.failure
,但无论哪种方式,您都知道将调用闭包。确保模型更新和 UI 更新发生在主队列上。通常,我们会将
retrieveData
对闭包的调用分派到主队列,这样调用者就不会受到这些的阻碍。(例如,这就是像 Alamofire 这样的库所做的。)
推荐阅读
- python - torch.save(model.state_dict()) 行出现错误,而模型编译训练并试图保存它我该如何解决?
- reactjs - Ant设计Form.list使用预填充数据?
- gitlab - 将脚本附加到一个阶段 .gitlab-ci.yml
- pine-script - 使用最后一根(吞没)蜡烛作为止损
- bash - 如何使用 bash 脚本运行 sftp 子命令?
- python - Rpy2将R数据框转换为熊猫
- unity3d - 一个对象如何不受其他对象的影响
- python - 如何在python中将不同数量的参数从元组传递到字符串格式?
- php - 在codeigniter中将多维数组加载到视图中
- javascript - Javascript随机元素,不重复最后一个