我正在学习Swift但我在ViewDidLoad中有一个Int类型的Variable(Followers),我将该值设置为默认值0。然后我做一个返回1个数组的Json Request,并将Followers的值设置为Json数组中788的数字。然而,当我之后进行打印时,值保持为0.这是我的代码,它会更有意义
override func viewDidLoad() {
super.viewDidLoad()
var followers = 0
// Sent HTTP Request
sessionn.dataTask(with:requestt, completionHandler: {(data, response, error) in
if error != nil {
// print(error)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:Any]
if let Profiles = parsedData["data"] as! [AnyObject]? {
for Profiles in Profiles {
if let follow = Profiles["followers"] as? Int {
self.followers = follow
// The value here says 788
print(self.followers)
}
}
DispatchQueue.main.async {
}
}
} catch let error as NSError {
print(error)
}
}
}).resume()
print("Followers is")
// The value here says 0 every time
print(followers)
// I have even tried
print(self.followers)
}
正如你所看到的追随者变量设置为0当我执行我的HttpPost时,我可以看到当我有打印(self.followers)时,变量设置为788但是当我访问变量时循环它的值会回到0。当我通过构建应用程序学习Swift时,如何纠正这个错误。
答案 0 :(得分:3)
您误解了异步代码的工作原理。
当您设置NSSession
数据任务时,在发出网络请求之前,会立即回复task.resume()
。
您应该将处理响应的代码放在完成处理程序中。即使您在网络任务上调用resume后发生了The value here says 0
打印语句,但尚未检索到数据。
想象一下,你正在做晚餐,然后你把孩子送去买一袋面粉。你说"孩子,给我一些面粉。当你回来时,按下公寓门上的蜂鸣器,我就会把你嗡嗡响。"
然后你回到烹饪晚餐的其他部分,但你不要指望你告诉你的孩子去面粉的那一刻,你会瞧不起柜台,面粉将是那里。你知道你必须要等到蜂鸣器发出嗡嗡声,然后你的孩子才会回来吃面粉。
提交网络任务就是这样。对task.resume()
的调用类似于您对面粉的要求。您提交请求,但在请求完成处理之前,您继续执行您正在执行的操作。 完成处理程序正在运行的是蜂鸣器,让您知道您的孩子已经回来了。
我在Github上创建了一个项目,演示了如何在URLSession中使用完成处理程序。该项目名为Async_demo(链接)
关键部分是DownloadManager.swift
中的方法downloadFileAtURL()
注意该函数如何将完成处理程序作为参数。该函数使用完成处理程序创建URLSession数据任务。在完成处理程序内,对于URLSession
数据任务,downloadFileAtURL()
函数调用传递给它的完成处理程序。它使用DispatchQueue.main.async()
来调用主线程上的完成处理程序。
此演示项目使用URLSession
数据任务,并明确禁用数据缓存,以便每次单击下载按钮时都会重新加载图像。
以下是DownloadManager.swift中的downloadFileAtURL()
函数的代码:
func downloadFileAtURL(_ url: URL, completion: @escaping DataClosure) {
//We create a URLRequest that does not allow caching so you can see the download take place
let request = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 30.0)
let dataTask = URLSession.shared.dataTask(with: request) {
data, response, error in
//Perform the completion handler on the main thread
DispatchQueue.main.async {
//Call the copmletion handler that was passed to us
completion(data, error)
}
}
dataTask.resume()
//When we get here the data task will NOT have completed yet!
}
视图控制器有一个名为handledDownloadButton()
的IBAction函数。那个功能: