ChatGPT解决这个技术问题 Extra ChatGPT

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

我在 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 的任何其他用途......

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


r
rickster

从一开始,Swift 就提供了一些使 ObjC 和 C 更加 Swifty 的工具,每个版本都添加了更多功能。现在,在 Swift 3 中,新的 "import as member" 功能允许具有某些样式的 C API 的框架——其中你有一个工作起来有点像一个类的数据类型,以及一堆与之一起工作的全局函数——发挥更多作用像 Swift 原生 API。数据类型作为 Swift 类导入,它们相关的全局函数作为这些类的方法和属性导入,并且一些相关的东西(如常量集)可以在适当的情况下成为子类型。

在 Xcode 8 / Swift 3 beta 中,Apple 已应用此功能(以及其他一些功能)来使 Dispatch 框架更加 Swifty。 (还有 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

顺便说一句,如果您保留自己的队列来组织工作,那么现在获取队列的方法如下所示(注意 DispatchQueueAttributesOptionSet,因此您使用集合样式的文字来组合选项):

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 项目/playground 中放置一个符号(如 DispatchQueue)并按命令单击它,然后从那里绕过模块。 (您可以在 Apple 漂亮的新 API 参考网站和 in-Xcode 文档查看器中找到 Swift Dispatch API,但看起来 C 版本的文档内容尚未移入其中。)

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


至于 Xcode 8 Beta 6, .serial 属性消失了,默认行为 - forums.developer.apple.com/message/159457#159457
自 XCode 8.1 以来,这需要更新。属性标签已经消失,我们可以使用 'DispatchQueue.global(qos: .background).async'
精彩的答案。真的帮助我解决了这个问题。
我必须使用 qos: 而不是 attributes:
这不应该是 class Foo 示例中的 myQueue.async { 吗?
p
pkamb

在 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")
})

所以它不会阻止用户界面?
S
S. Matsepura

这是关于 asyncSwift 4 的一个很好的例子:

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

hi DispatchQueue.main.async { // Run UI Updates } 在后台线程之前执行
类似于 Kotlin 的协程
p
pkamb

在 Xcode 8 中使用:

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

S
Saranjith

Swift 5.2、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 } 

异步线程将与主线程一起工作。

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


以及如何在不阻塞主线程 (UI) 的情况下使用同步线程?我想在后台执行一排事情——但是这些事情必须以同步的方式一个接一个地执行。在此期间,用户界面应该保持响应......你会怎么做?
使用 NSOperationQueue。您的每个任务代表一个 NSOperation。参考stackoverflow.com/a/19746890/5215474
拯救了我的一天!谢谢!
G
Gurjinder Singh

Swift 4.1 和 5。我们在代码中的很多地方都使用了队列。因此,我创建了包含所有队列的 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 {
        //Update UI
    }
}

太好了,谢谢!