ios - 理解为什么我需要分派(dispatch)回主线程

标签 ios multithreading

我只是想澄清一些对我来说有点不清楚的事情。考虑以下异步执行闭包的代码:

func fetchImage(completion: UIImage? -> ()) {
  dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
    // fetch the image data over the internet

    // ... assume I got the data
    let image = UIImage(data: data)
    dispatch_async(dispatch_get_main_queue()) {
      completion(image)
    }
  }
}

据我了解,我们需要分派(dispatch)回主线程的原因是调用完成闭包以返回图像需要更长的时间。

不过,我觉得这个观点有点俗气。例如,我还想创建一个 isLoading 属性,用于防止同时发生多个网络调用:

func fetchImage(completion: UIImage? -> ()) {
  // if isLoading is true, then don't continue getting the image because I want only 1 network operation to be running at 1 time.
  if isLoading { 
    completion(nil)
    return 
  }

  isLoading = true
  dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
    let image = UIImage(data: data)

    // image creation is complete. Set isLoading to false to allow new fetches
    self.isLoading = false
    dispatch_async(dispatch_get_main_queue()) {
      completion(image)
    }
  }
}

对于上面的代码片段,我的问题是 - 我应该将 self.isLoading = false 放在主队列的调度 block 中吗?还是微不足道?

感谢所有建议!

最佳答案

这并不是说“否则会花费更长的时间”,而是对 UI 的所有更新必须在主队列上执行,以防止自动布局并发更新可能发生的损坏环境或其他非线程安全的 UI 数据结构。

在 iOS 的早期版本中,不更新主线程上的 UI 的常见副作用是升级出现延迟,但是从 iOS 9 开始,您将遇到异常。

就您的问题而言,您的代码最好表现一致。 IE。要么总是在主队列上分派(dispatch)完成处理程序,要么从不这样做。这将使编写完成 block 的程序员知道他们是否需要调度 UI 更新。

最好在加载完成后立即将 isLoading 设置为 false,因此最好在 dispatch_async 之外。

鉴于您的函数正在检索 UIImage,调用者很有可能会更新 UI,因此在主线程上分派(dispatch)完成处理程序可能是“很好”的做法。

关于ios - 理解为什么我需要分派(dispatch)回主线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36367509/

相关文章:

java - 写时复制和比较然后交换之间的区别?

ios - 设置推送通知的标题?

ios - 当我在 tabBarController 中的选项卡之间切换时会调用哪个方法?

c# - 同步/阻塞 Application.Invoke() for GTK#

sql - .NET - 如何将 BackgroundWorker 与 CMD.executenonquery 一起使用

java - 是否允许 JVM 围绕 AtomicInteger 调用重新排序指令

ios - 导航栏按钮不显示在导航栏中

iphone - 开始使用核心数据

iphone - 在 iOS 中从纬度和经度获取位置名称

python threading.Event : add event params