【问题标题】:What is dispatch_async function in iOS?iOS 中的 dispatch_async 函数是什么?
【发布时间】:2015-11-05 21:52:48
【问题描述】:

我试图通过阅读来理解这一点:https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/

但这太令人困惑了。我知道以下代码必须对任务进行排队。我认为排队意味着等待?而且我不确定任务是什么。而且我知道它以某种方式加速了该代码中的代码的执行。尽管如此,我还是很困惑何时使用它以及为什么使用它。

dispatch_async(dispatch_get_main_queue(), { () -> Void in    
})

以上代码可在这段代码中找到:

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var cityTextField: UITextField!
@IBOutlet weak var resultLabel: UILabel!
@IBAction func findWeather(sender: AnyObject) {
    let url = NSURL(string: "http://www.weather-forecast.com/locations/Riverside/forecasts/latest")!
    let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
        if let urlContent = data {
            let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding)

            var websiteArray = webContent!.componentsSeparatedByString("3 Day Weather Forecast Summary:</b><span class=\"read-more-small\"><span class=\"read-more-content\"> <span class=\"phrase\">")
            let tempText = websiteArray[1]

            websiteArray = tempText.componentsSeparatedByString("</span></span></span></p><div class=\"forecast-cont\"><div class=\"units-cont\"><a class=\"units metric active\">&deg;C</a><a class=\"units imperial\">&deg;")
            print(websiteArray[0])
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.resultLabel.text = websiteArray[0]
            })

        }
    }
    task?.resume()
}

【问题讨论】:

    标签: ios grand-central-dispatch


    【解决方案1】:

    简而言之,dispatch_async 块中的代码将在您选择的队列(线程)上异步执行(主队列是 UI 线程)

    为什么它会加速你的代码,因为self.resultLabel.text = websiteArray[0] 不在一个可以在主线程上运行的块中,这会使代码在不是 UI 线程的不同线程上执行(因为 NSURLSession 完成处理程序发生在不同的线程),并且不在 UI 线程上更新 UI 会导致奇怪的行为(主要是更新 UI 时的随机延迟)

    如果您将 dispatch_get_main_queue() 更改为不同的队列,您会看到与完全没有阻塞完全相同的行为

    也许这将有助于澄清哪一行代码在哪个线程上执行:

    @IBAction func findWeather(sender: AnyObject) { //function called from UI thread
        let url = NSURL(string: "http://www.weather-forecast.com/locations/Riverside/forecasts/latest")! //UI thread
        let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in //UI thread, but this function call now creates its own thread that the block will run on
    //Not UI Thread ----------------------------
            if let urlContent = data {  
                let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding)
    
                var websiteArray = webContent!.componentsSeparatedByString("3 Day Weather Forecast Summary:</b><span class=\"read-more-small\"><span class=\"read-more-content\"> <span class=\"phrase\">")
                let tempText = websiteArray[1]
    
                websiteArray = tempText.componentsSeparatedByString("</span></span></span></p><div class=\"forecast-cont\"><div class=\"units-cont\"><a class=\"units metric active\">&deg;C</a><a class=\"units imperial\">&deg;")
                print(websiteArray[0])
    // -----------------------------------------
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.resultLabel.text = websiteArray[0] //UI thread
                })
    //Not UI Thread again, if there was code here
            }
        }
        task?.resume() //inside the original function, so its on the UI thread
    }
    

    【讨论】:

    • 嘿,看来您需要了解一些基础知识。队列和线程基本上是一样的东西,只是术语不同(有一些区别虽然你不需要担心),但基本上,当程序启动时,操作系统会启动一个进程,这是你的应用程序,应用程序可以有多个线程,就像在您的应用程序中拥有所有同时运行的迷你应用程序一样(因此为什么多核 CPU 对于同时运行多个线程很有用)。线程只是像正常一样执行代码,但与其他线程同时执行。
    • 所以当你启动一个 NSURLSession 时,它发生在另一个线程上,所以你的主 UI 线程不会被阻塞并且必须等待你的 web 服务返回才能继续。所以它改为启动另一个线程来等待,然后你需要让它在主线程上更新你的ui,而不是它等待的这个新线程
    • 是的,几乎...没有块,它确实等到 NSURLSession 结束,但更重要的是,它在与 NSURLSession 相同的线程上运行该行代码,这不是主线程所有 UI 更新都必须发生的地方。因此引入在主线程上运行的块,使代码在 URLSession 结束后发生,但随后返回 UI 线程,以便 UI 正确更新......除非这就是你的意思,那么你是正确的
    • 恐怕没有任何资源,但谷歌是你的朋友。但是为了进一步澄清,在 dataTaskWithURL 函数内部,它在幕后有效地调用了它自己的 dispatch_async 块,而不是 dispatch_get_main_queue() 和它自己的块内部,一旦它完成从互联网检索,它调用你拥有的块在同一线程上的代码中定义,这就是为什么在那里进行 UI 更新不能很好地工作的原因,所以在您的 (NSURLSession) 块中,您正在创建自己的块以在 ui 线程上运行,以便 ui 正确更新。
    • 把它想象成火车轨道,每个轨道都是一个线程。您从一个轨道(UI 轨道)开始,然后当您调用 NSURLSession 时,它将轨道分成 2 个,然后 URLSession 火车可以在那里等待,而 UI 火车可以在原始 UI 轨道上传递它。当 URLSession 列车再次运行时,它会沿着自己的轨道移动以进行一些处理,但是现在当它需要更新 UI 时,它无法在自己的轨道上执行此操作,因此必须合并回 UI 轨道,即dispatch_async 块可以让你做什么
    【解决方案2】:
    dispatch_async(dispatch_get_main_queue(), { () -> Void in    
                    self.resultLabel.text = websiteArray[0]
    })
    

    上述函数用于在主线程上进行更新,任何与 UI 更新相关的操作都应在主线程上进行 & 因为dispatch_get_main_queue() 作为参数传递。

    如果您删除此块并尝试在没有它的情况下设置结果值文本,则它可能不会更新 UI 或者需要时间来更新它。

    尝试设置不同的队列,让你更清楚。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-24
      • 2015-04-18
      • 2014-03-26
      相关资源
      最近更新 更多