22

如何讓代碼等待,直到DispatchQueue中的任務結束?它是否需要任何CompletionHandler或什麼?等待任務完成

func myFunction() { 
    var a: Int? 

    DispatchQueue.main.async { 
     var b: Int = 3 
     a = b 
    } 

    // wait until the task finishes, then print 

    print(a) // - this will contain nil, of course, because it 
      // will execute before the code above 

} 

我使用的Xcode 8.2和寫入斯威夫特3.

回答

59

使用DispatchGroup s到實現這一目標。您可以得到通知時,該集團的enter()leave()電話是平衡的:

func myFunction() { 
    var a: Int? 

    let group = DispatchGroup() 
    group.enter() 

    DispatchQueue.main.async { 
     a = 1 
     group.leave() 
    } 

    // does not wait. But the code in notify() gets run 
    // after enter() and leave() calls are balanced 

    group.notify(queue: .main) { 
     print(a) 
    } 
} 

,或者你可以等待(和返回):

func myFunction() -> Int? { 
    var a: Int? 

    let group = DispatchGroup() 
    group.enter() 

    // avoid deadlocks by not using .main queue here 
    DispatchQueue.global(attributes: .qosDefault).async { 
     a = 1 
     group.leave() 
    } 

    // wait ... 
    group.wait() 

    // ... and return as soon as "a" has a value 
    return a 
} 

注意group.wait()塊當前隊列(可能是主隊列在你的情況),所以你必須在另一個隊列dispatch.async(如上面的示例代碼),以避免的死鎖。

+0

我想在另一個類中執行一個函數,但我想等待完成該函數,然後在當前類中繼續如何處理該函數? –

+1

@SaeedRahmatolahi:或者使用'wait'方法(如果你沒有問題阻止,即如果你不在主線程中),或者提供一個完成處理程序或在你的調用類中使用notify方法。 – shallowThought

+0

爲什麼你要在異步塊外調用'group.enter'?每個區塊都有責任進入和離開組織嗎? – Bill

1

使用派遣組

dispatchGroup.enter() 
    FirstOperation(completion: { _ in 
dispatchGroup.leave() 
    }) 
    dispatchGroup.enter() 
    SecondOperation(completion: { _ in 
dispatchGroup.leave() 
    }) 
    dispatchGroup.wait() //Waits here on this thread until the two operations complete executing. 
+1

假設你把這個主隊列中,這會導致死鎖。 – shallowThought

+0

@shallowThought如此真實。 – Prateekro

+0

我想在另一個類中執行一個函數,但我想等待完成該函數,然後在當前類中繼續如何處理該函數? –

11

在Swift 3中,當DispatchQueue完成一項任務時,不需要完成處理程序。 此外,你可以用不同的方式實現你的目標

一種方法是這樣的。

var a: Int? 

    let queue = DispatchQueue(label: "com.app.queue") 
    queue.sync { 

     for i in 0..<10 { 

      print("Ⓜ️" , i) 
      a = i 
     } 
    } 

    print("After Queue \(a)") 

它將等到循環結束,但在這種情況下,您的郵件線程將被阻止。

你也可以做同樣的事情,這樣的

let myGroup = DispatchGroup() 
    myGroup.enter() 
    //// Do your task 

    myGroup.leave() //// When your task completes 
    myGroup.notify(queue: DispatchQueue.main) { 

     ////// do your remaining work 
    } 

最後一件事。如果要在使用DispatchQueue完成任務時使用completionHandler,則可以使用DispatchWorkItem

下面是一個例子,如何使用DispatchWorkItem

let workItem = DispatchWorkItem { 
    // Do something 
} 

let queue = DispatchQueue.global() 
queue.async { 
    workItem.perform() 
} 
workItem.notify(queue: DispatchQueue.main) { 
    // Here you can notify you Main thread 
}