如何在Swift 3,Swift 4及更高版本中dispatch_sync,dispatch_async,dispatch_after等?

问题描述 投票:221回答:6

我在Swift 2.x(甚至1.x)项目中有很多代码,如下所示:

// Move to a background thread to do some long running work
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    let image = self.loadOrGenerateAnImage()
    // Bounce back to the main thread to update the UI
    dispatch_async(dispatch_get_main_queue()) {
        self.imageView.image = image
    }
}

或者像这样的东西来延迟执行:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
    print("test")
}

或者Grand Central Dispatch API的各种其他用途......

现在我已经在Swift 3的Xcode 8(beta)中打开了我的项目,我得到了各种各样的错误。其中一些提供修复我的代码,但并非所有修复产生工作代码。我该怎么办?

swift grand-central-dispatch dispatch-async swift3 libdispatch
6个回答
322
投票

从一开始,Swift就提供了一些使ObjC和C更加Swifty的工具,每个版本都增加了更多。现在,在Swift 3中,新的"import as member"特性允许具有某些样式的C API的框架 - 在这里你有一种类似于类的数据类型,以及一组使用它的全局函数 - 更像是Swift - 原始API。数据类型作为Swift类导入,它们的相关全局函数作为这些类的方法和属性导入,并且一些相关的事物(如常量集)可以在适当的时候成为子类型。

在Xcode 8 / Swift 3 beta中,Apple已经应用了这一功能(以及其他一些功能),使Dispatch框架更加灵活。 (还有Core Graphics。)如果你一直在关注Swift开源工作,this isn't news,但现在它是第一次成为Xcode的一部分。

将任何项目移动到Swift 3的第一步应该是在Xcode 8中打开它,然后在菜单中选择Edit> Convert> To Current Swift Syntax ....这将适用于(通过您的审核和批准)所有重命名的API和其他更改所需的所有更改。 (通常,一行代码会同时受到多个这些更改的影响,因此响应错误修复 - 它可能无法正确处理所有内容。)

结果是弹跳工作到后台和后面的常见模式现在看起来像这样:

// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
    let image = self.loadOrGenerateAnImage()
    // Bounce back to the main thread to update the UI
    DispatchQueue.main.async {
        self.imageView.image = image
    }
}

请注意,我们使用.userInitiated而不是旧的DISPATCH_QUEUE_PRIORITY常量之一。 OS X 10.10 / iOS 8.0中引入了服务质量(QoS)说明符,为系统确定工作优先级和弃用旧优先级说明符提供了更清晰的方法。有关详细信息,请参阅Apple的docs on background work and energy efficiency

顺便说一句,如果你保持自己的队列来组织工作,现在获得一个的方式看起来像这样(注意DispatchQueueAttributes是一个OptionSet,所以你使用集合式文字来组合选项):

class Foo { 
    let queue = DispatchQueue(label: "com.example.my-serial-queue",
                           attributes: [.serial, .qosUtility])
    func doStuff() {
        queue.async {
            print("Hello World")
        }
    }
}

使用dispatch_after以后再做?这也是队列上的一种方法,它需要一个DispatchTime,它有各种数字类型的运算符,所以你可以添加整数或小数秒:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // in half a second...
    print("Are we there yet?")
}

您可以通过在Xcode 8中打开它的界面来找到绕过新Dispatch API的方法 - 使用Open Quickly查找Dispatch模块,或者在Swift项目/游乐场中放置一个符号(如DispatchQueue)并命令单击它,然后brouse从那里到模块周围。 (您可以在Apple的spiffy新API参考网站和in-Xcode文档查看器中找到Swift Dispatch API,但看起来C版本的文档内容还没有进入它。)

有关更多提示,请参阅Migration Guide


133
投票

在Xcode 8 beta 4不起作用......

使用:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    print("Are we there yet?")
}

对于异步两种方式:

DispatchQueue.main.async {
    print("Async1")
}

DispatchQueue.main.async( execute: {
    print("Async2")
})

67
投票

这个是Swift 4关于async的好例子:

DispatchQueue.global(qos: .background).async {
    // Background Thread
    DispatchQueue.main.async {
        // Run UI Updates or call completion block
    }
}

37
投票

在Xcode 8中使用:

DispatchQueue.global(qos: .userInitiated).async { }

20
投票

斯威夫特4

主要和后台队列

let main = DispatchQueue.main
let background = DispatchQueue.global()
let helper = DispatchQueue(label: "another_thread") 

使用异步和同步线程!

 background.async { //async tasks here } 
 background.sync { //sync tasks here } 

异步线程将与主线程一起使用。

同步线程将在执行时阻止主线程。


6
投票

Swift 4.1。我们在代码中的许多地方使用队列。所以,我创建了包含所有队列的Threads类。如果您不想使用Threads类,则可以从类方法中复制所需的队列代码。

class Threads {

  static let concurrentQueue = DispatchQueue(label: "AppNameConcurrentQueue", attributes: .concurrent)
  static let serialQueue = DispatchQueue(label: "AppNameSerialQueue")

  // Main Queue
  class func performTaskInMainQueue(task: @escaping ()->()) {
    DispatchQueue.main.async {
      task()
    }
  }

  // Background Queue
  class func performTaskInBackground(task:@escaping () throws -> ()) {
    DispatchQueue.global(qos: .background).async {
      do {
        try task()
      } catch let error as NSError {
        print("error in background thread:\(error.localizedDescription)")
      }
    }
  }

  // Concurrent Queue
  class func perfromTaskInConcurrentQueue(task:@escaping () throws -> ()) {
    concurrentQueue.async {
      do {
        try task()
      } catch let error as NSError {
        print("error in Concurrent Queue:\(error.localizedDescription)")
      }
    }
  }

  // Serial Queue
  class func perfromTaskInSerialQueue(task:@escaping () throws -> ()) {
    serialQueue.async {
      do {
        try task()
      } catch let error as NSError {
        print("error in Serial Queue:\(error.localizedDescription)")
      }
    }
  }

  // Perform task afterDelay
  class func performTaskAfterDealy(_ timeInteval: TimeInterval, _ task:@escaping () -> ()) {
    DispatchQueue.main.asyncAfter(deadline: (.now() + timeInteval)) {
      task()
    }
  }
}

显示主队列使用的示例。

override func viewDidLoad() {
    super.viewDidLoad()
     Threads.performTaskInMainQueue {
        self.tblViewSignUP.reloadData()
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.