Operation Queue vs Dispatch Queue for iOS Application

前端 未结 3 1260
天命终不由人
天命终不由人 2020-12-13 05:48
  1. What are the differences between Operation Queue and Dispatch Queue?
  2. Under what circumstances will it be more appropriate to use each?
3条回答
  •  猫巷女王i
    2020-12-13 06:37

    One common misconception about GCD is that “once you schedule a task it can’t be canceled, you need to use the Operation API for that”. With iOS 8 & macOS 10.10 DispatchWorkItem was introduced, which provides this exact functionality in an easy to use API.

    As I read in Apple developer documentation for DispatchQueue, now you can cancel your task from execution. For that, you have to work with DispatchWorkItem while using GCD over OperationQueue.

    • A dispatch work item has a cancel flag. If it is cancelled before running, the dispatch queue won’t execute it and will skip it. If it is cancelled during its execution, the cancel property return true. In that case, we can abort the execution. Also work items can notify a queue when their task is completed.

    Note: GCD doesn’t perform preemptive cancelations. To stop a work item that has already started, you have to test for cancelations yourself.

    As in below example, I checked like the following code

    if (task?.isCancelled)! {
          break;
       }
    

    Definition by Apple

    A DispatchWorkItem encapsulates work to be performed on a dispatch queue or within a dispatch group. You can also use a work item as a DispatchSource event, registration, or cancellation handler.

    I took the below example from SwiftIndia's Medium post. For more details please follow Apple documentation and SwiftIndia's Medium Post.

    import Foundation
    import PlaygroundSupport
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    
    let concurrentQueue = DispatchQueue(label: "com.queue.Concurrent", attributes: .concurrent)
    
    func performAsyncTaskInConcurrentQueue() {
        var task:DispatchWorkItem?
    
        task = DispatchWorkItem {
            for i in 1...5 {
                if Thread.isMainThread {
                    print("task running in main thread")
                } else{
                    print("task running in other thread")
                }
    
                if (task?.isCancelled)! {
                    break
                }
    
                let imageURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
                let _ = try! Data(contentsOf: imageURL)
                print("\(i) finished downloading")
            }
            task = nil
        }
    
        /*
         There are two ways to execute task on queue. Either by providing task to execute parameter or
         within async block call perform() on task. perform() executes task on current queue.
         */
        // concurrentQueue.async(execute: task!)
    
        concurrentQueue.async {
            task?.wait(wallTimeout: .now() + .seconds(2))
            // task?.wait(timeout: .now() + .seconds(2))
            task?.perform()
        }
        concurrentQueue.asyncAfter(deadline: .now() + .seconds(2), execute: {
            task?.cancel()
        })
    
        task?.notify(queue: concurrentQueue) {
            print("\n############")
            print("############")
            print("###### Work Item Completed")
        }
    }
    
    performAsyncTaskInConcurrentQueue()
    
    print("###### Download all images asynchronously and notify on completion ######")
    print("############")
    print("############\n")
    

提交回复
热议问题