【问题标题】:How to create dispatch queue in Swift 3如何在 Swift 3 中创建调度队列
【发布时间】:2016-10-14 19:47:01
【问题描述】:

在 Swift 2 中,我可以使用以下代码创建队列:

let concurrentQueue = dispatch_queue_create("com.swift3.imageQueue", DISPATCH_QUEUE_CONCURRENT)

但这在 Swift 3 中无法编译。

在 Swift 3 中编写此代码的首选方式是什么?

【问题讨论】:

  • Swift 4 有 3 个额外的参数来创建一个串行队列。如何使用它们来创建串行队列? DispatchQueue.init(label: , qos: , attributes: , autoreleaseFrequency: , target: )
  • @nr5 队列默认是串行的,所以只使用DispatchQueue(label: "your-label") 作为串行队列就足够了。额外的参数都有默认值。

标签: ios swift3 xcode8 grand-central-dispatch dispatch-after


【解决方案1】:

创建并发队列

let concurrentQueue = DispatchQueue(label: "queuename", attributes: .concurrent)
concurrentQueue.sync {

}  

创建串行队列

let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync { 

}

异步获取主队列

DispatchQueue.main.async {

}

同步获取主队列

DispatchQueue.main.sync {

}

获取后台线程之一

DispatchQueue.global(qos: .background).async {

}

Xcode 8.2 beta 2:

获取后台线程之一

DispatchQueue.global(qos: .default).async {

}

DispatchQueue.global().async {
    // qos' default value is ´DispatchQoS.QoSClass.default`
}

如果您想了解如何使用这些队列。请参阅answer

【讨论】:

  • 创建串行队列时实际上可以省略attributes: .seriallet serialQueue = DispatchQueue(label: "queuename")
  • 在 Xcode 8 beta 4 中没有 .serial 选项,因此您必须通过省略属性中的 .concurrent 来创建串行队列。
  • 我需要将 DispatchQueue 从 Swift3 访问到 objc,但出现以下错误无法初始化类型为 '__strong dispatch_queue_t' (aka 'NSObject *__strong') 的右值为OS_dispatch_queue * _Nonnull' 当做 dispatch_queue_t backgroundQueue = [SwiftClass Queue];那是 swift 中 DispatchQueue 的静态变量
  • DispatchQueue.main.asynchronously(DispatchQueue.main) { self.mapView.add(self.mapPolyline) } 在 Swift 3.0 我试过 DispatchQueue.global().asynchronously(DispatchQueue.main) { self.mapView.add(self.mapPolyline) } 但两者都显示与“dispathQuoue 类型的值没有异步成员”相同的错误
  • 从OP的代码来看,为什么苹果偏重使用"com.swift3.imageQueue"。我看到标签有 3 个部分。这是为什么?每个部分代表什么?我没有得到格式
【解决方案2】:

在 >=Swift 3 下编译。这个例子包含了我们需要的大部分语法。

QoS - 新的服务质量语法

weak self - 中断保留周期

如果 self 不可用,什么也不做

async global utility queue - 用于网络查询,不等待结果,它是一个并发队列,块(通常)在启动时不等待。并发队列的例外情况可能是,当先前已达到其任务限制时,该队列会暂时变为串行队列并等待该队列中的某个先前任务完成。

async main queue - 对于触摸 UI,块不等待结果,而是在开始时等待它的插槽。主队列是串行队列。

当然,你需要为此添加一些错误检查...

DispatchQueue.global(qos: .utility).async { [weak self] () -> Void in

    guard let strongSelf = self else { return }

    strongSelf.flickrPhoto.loadLargeImage { loadedFlickrPhoto, error in

        if error != nil {
            print("error:\(error)")
        } else {
            DispatchQueue.main.async { () -> Void in
                activityIndicator.removeFromSuperview()
                strongSelf.imageView.image = strongSelf.flickrPhoto.largeImage
            }
        }
    }
}

【讨论】:

  • 在 Swift 3 中编码时,习惯于压缩和删除 30% 之前的代码:-)
  • 感谢[弱自我]的例子!
  • guard最好不要在顶部selfnil,这样如果是nil就不会执行任何代码,例如guard strongSelf = self else { return }
  • @t1 你能告诉我在哪里可以找到用 Swift 3 代码编写的 GCD 文档吗? I have only found the one written in Objective C。这里有人指给我看 WWDC 的视频,但我想阅读带有 Swift 3 示例的官方文档,但找不到。
  • 不要将.global(qos: .background) 用于 IO(网络请求)。请改用.global(qos: .default).global(qos: .utility)
【解决方案3】:

在 XCode 8、Swift 3 中编译 https://github.com/rpthomas/Jedisware

 @IBAction func tap(_ sender: AnyObject) {

    let thisEmail = "emailaddress.com"
    let thisPassword = "myPassword" 

    DispatchQueue.global(qos: .background).async {

        // Validate user input

        let result = self.validate(thisEmail, password: thisPassword)

        // Go back to the main thread to update the UI
        DispatchQueue.main.async {
            if !result
            {
                self.displayFailureAlert()
            }

        }
    }

}

【讨论】:

    【解决方案4】:

    由于上面已经回答了 OP 问题,我只想添加一些速度注意事项:

    DispatchQueue.global 中为异步函数分配的优先级类别有很大不同。

    我不建议以 .background 线程优先级运行任务,尤其是在任务似乎分配在低功耗内核上的 iPhone X 上。

    以下是来自计算密集型函数的一些真实数据,该函数从 XML 文件(带有缓冲)读取并执行数据插值:

    设备名称/.background/.utility/.default/.userInitiated/。用户交互

    1. iPhone X:18.7s / 6.3s / 1.8s / 1.8s / 1.8s
    2. iPhone 7:4.6s / 3.1s / 3.0s / 2.8s / 2.6s
    3. iPhone 5s:7.3s / 6.1s / 4.0s / 4.0s / 3.8s

    请注意,并非所有设备的数据集都相同。它在 iPhone X 上是最大的,在 iPhone 5s 上是最小的。

    【讨论】:

    • 很棒的信息。帮助了我
    • @Myk 如果用户已经启动和/或正在等待结果,您应该使用 .userInitiated.userInteractive 以便任何其他操作回溯。在大多数其他情况下,.default 将是一个不错的选择。
    【解决方案5】:

    我这样做了,如果你想刷新你的 UI 以显示新数据而不像在 UITableView 或 UIPickerView 中那样引起用户注意,这一点尤其重要。

        DispatchQueue.main.async
     {
       /*Write your thread code here*/
     }
    

    【讨论】:

      【解决方案6】:

      Swift 5 的更新

      串行队列

      let serialQueue = DispatchQueue.init(label: "serialQueue")
      serialQueue.async {
          // code to execute
      }
      

      并发队列

      let concurrentQueue = DispatchQueue.init(label: "concurrentQueue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
      
      concurrentQueue.async {
      // code to execute
      }
      

      来自Apple documentation

      参数

      标签

      附加到队列的字符串标签,以便在调试工具(例如 Instruments、示例、堆栈快照和崩溃报告)中唯一标识它。因为应用程序、库和框架都可以创建自己的调度队列,所以建议使用反向 DNS 命名样式 (com.example.myqueue)。该参数是可选的,可以为NULL。

      qos

      与队列关联的服务质量级别。该值确定系统调度任务执行的优先级。有关可能值的列表,请参阅 DispatchQoS.QoSClass。

      属性

      与队列关联的属性。包含 concurrent 属性以创建并发执行任务的调度队列。如果省略该属性,调度队列会串行执行任务。

      自动释放频率

      自动释放由队列调度的块创建的对象的频率。有关可能值的列表,请参阅DispatchQueue.AutoreleaseFrequency

      目标

      执行块的目标队列。如果您希望系统提供适合当前对象的队列,请指定 DISPATCH_TARGET_QUEUE_DEFAULT。

      【讨论】:

        【解决方案7】:
         DispatchQueue.main.async {
                  self.collectionView?.reloadData() // Depends if you were populating a collection view or table view
            }
        
        
        OperationQueue.main.addOperation {
            self.lblGenre.text = self.movGenre
        }
        

        //如果您需要在视图控制器上填充对象(标签、图像视图、文本视图),请使用操作队列

        【讨论】:

          【解决方案8】:
             let concurrentQueue = dispatch_queue_create("com.swift3.imageQueue", DISPATCH_QUEUE_CONCURRENT) //Swift 2 version
          
             let concurrentQueue = DispatchQueue(label:"com.swift3.imageQueue", attributes: .concurrent) //Swift 3 version
          

          我在 Xcode 8、Swift 3 中重新编写了您的代码,并且这些更改与您的 Swift 2 版本形成对比。

          【讨论】:

          • 这看起来比我写的更干净。谢谢。
          【解决方案9】:

          斯威夫特 3

          你想在 swift 代码中调用一些闭包,然后你想在故事板中进行更改,任何类型的更改都属于视图,你的应用程序将崩溃

          但你想使用调度方法你的应用程序不会崩溃

          异步方法

          DispatchQueue.main.async 
          {
           //Write code here                                   
          
          }
          

          同步方法

          DispatchQueue.main.sync 
          {
               //Write code here                                  
          
          }
          

          【讨论】:

          • 我想在服务调用时使用异步方法我的代码是 DispatchQueue.main.async { let objstory1 = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController _ = self.navigationController?.pushViewController(objstory1, animated: false) }
          • 永远不要使用DispatchQueue.main.sync
          • 在主队列上同步调用肯定会出问题。
          【解决方案10】:
          DispatchQueue.main.async(execute: {
          
          // write code
          
          })
          

          串行队列:

          let serial = DispatchQueue(label: "Queuename")
          
          serial.sync { 
          
           //Code Here
          
          }
          

          并发队列:

           let concurrent = DispatchQueue(label: "Queuename", attributes: .concurrent)
          
          concurrent.sync {
          
           //Code Here
          }
          

          【讨论】:

          • 这不会创建一个调度队列,它只是在运行循环一个滴答后把你放在主队列上。
          【解决方案11】:

          对于 Swift 3

             DispatchQueue.main.async {
                  // Write your code here
              }
          

          【讨论】:

          • @Moritz 很遗憾,我完全同意。
          【解决方案12】:
           let newQueue = DispatchQueue(label: "newname")
           newQueue.sync { 
          
           // your code
          
           }
          

          【讨论】:

            【解决方案13】:
            DispatchQueue.main.async(execute: {
               // code
            })
            

            【讨论】:

            • 感谢您提供此代码 sn-p,它可能会提供一些即时帮助。一个正确的解释would greatly improve 其教育价值通过展示为什么这是一个很好的解决问题的方法,并将使它对未来有类似但不相同的问题的读者更有用。请edit您的答案添加解释,并说明适用的限制和假设。
            【解决方案14】:

            现在很简单:

            let serialQueue = DispatchQueue(label: "my serial queue")
            

            默认是串行的,要获得并发,你可以使用可选的属性参数 .concurrent

            【讨论】:

            • 您最好通过添加seiralQueue.async {} 来更新您的答案。 @tylemol
            【解决方案15】:

            您可以在 swift 3.0 中使用此代码创建调度队列

            DispatchQueue.main.async
             {
               /*Write your code here*/
             }
            
               /* or */
            
            let delayTime = DispatchTime.now() + Double(Int64(0.5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)                   
            DispatchQueue.main.asyncAfter(deadline: delayTime)
            {
              /*Write your code here*/
            }
            

            【讨论】:

            • 抱歉,这不是创建一个调度队列,而是在运行循环一次滴答后访问主队列。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-06-10
            • 1970-01-01
            • 2021-10-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多