对不起,如果这是一个noobish问题,但我不知道收到API请求后执行代码块与通过GCD,委托和闭包解析之间的区别。
据我所知,创建一个从API URL下载数据的会话是在主线程上完成的,除非我在GCD块或委托或闭包内执行代码。
以下是两个例子: 使用GCD
DispatchQueue.global(qos: .utility).async {
let requestURL = URL(string: "http://echo.jsontest.com/key/value/one/two")
let session = URLSession.shared
let task = session.dataTask(with: requestURL!) {
(data, response, error) in
print(data as Any)
DispatchQueue.main.async {
print("Hello")
}
}
task.resume()
}
使用委托:
import Foundation
import UIKit
protocol WeatherDataDownloaderProtocol {
func setData(weatherData: WeatherData)
}
class WeatherDataDownloader {
var weatherData = WeatherData()
var delegate: WeatherDataDownloaderProtocol?
func downloadWeatherData() {
let API_URL = WEATHER_FORECAST_URL
guard let URL = URL(string: API_URL) else {
print("Error: No valid URL")
return
}
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: URL) { (data, response, error) in
guard error == nil else {
print("Error getting data")
print("\(error)")
return
}
guard let responseData = data else {
print("Error: Did not receive data")
return
}
do {
guard let JSON = try JSONSerialization.jsonObject(with: responseData, options: []) as? Dictionary<String, AnyObject> else {
print("Error: Error trying to convert data to JSON")
return
}
print(JSON)
self.sendDataBack()
} catch {
print("Error: Parsing JSON data error")
return
}
}
task.resume()
}
func sendDataBack() {
if let _delegate = delegate {
_delegate.setData(weatherData: weatherData)
}
}
}
在检索和解析JSON之后,print(“Hello”)和print(JSON)+ self.sendDataBack()都将执行。两种方法有什么区别?如果我在等待网络响应时导航出viewController,是否与我的应用程序崩溃有关?
非常感谢
答案 0 :(得分:2)
在您的第一种方法中,URLSession
调用不是必需的。 dataTask
{{1}}是后台任务。
因此,选择不是GDC与代表,而是完成处理程序与委托。
基于意见:
使用委托更加工作,更难阅读,因为如果委托实际设置了,那么必须检查代码的其他区域以及它是谁以及它实际上做了什么。
如果在您的网络呼叫结束时代理不再存在,也不会执行任何代码。因此,对于这种情况,我请求使用完成闭包。
答案 1 :(得分:1)
两者都是正确的。块/闭包方法更新,并且被认为具有更好的可读性,因为您不必在函数之间跳转,甚至在文件之间跳转以遵循代码的过程。
答案 2 :(得分:1)
DispatchQueue.global(qos: .utility).async {
let requestURL = URL(string: "http://echo.jsontest.com/key/value/one/two")
let session = URLSession.shared
let task = session.dataTask(with: requestURL!) {
(data, response, error) in
print(data as Any)
DispatchQueue.main.async {
print("Hello")
}
}
task.resume()
}
在此方法中,您的服务在后台线程中命中,当您完成后台线程时,您将使用此方法返回main
线程
DispatchQueue.main.async {
print("Hello")
}
然后你的print("Hello")
将在主线程中调用。
而方法
downloadWeatherData
appdelegate
中定义的也会在后台线程中以closure
的方式命中服务,因为closure
也像后台线程一样工作。当任务完成时,使用closure
会自动返回主线程,您可以在其中调用print(JSON)
。
现在出现问题,最好的事情是你应该等到你的任务完成,然后在你的viewcontroller上得到json响应,然后移动到你的下一个控制器,在某些情况下你的应用可能会崩溃。