DispatchQueue vs代理与Swift中的闭包

时间:2017-05-16 13:03:49

标签: ios swift delegates grand-central-dispatch

对不起,如果这是一个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,是否与我的应用程序崩溃有关?

非常感谢

3 个答案:

答案 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响应,然后移动到你的下一个控制器,在某些情况下你的应用可能会崩溃。