it-swarm.com.ru

В ожидании завершения задачи

Как я могу заставить свой код ждать, пока задача в 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 и пишу в Swift 3.

55
Bartosz Woźniak

Используйте DispatchGroups для достижения этой цели. Вы можете получить уведомление, когда вызовы группы 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() блокирует текущую очередь (вероятно, основную очередь в вашем случае), поэтому вам нужно отправлять файл .async в другую очередь (как в примере кода выше), чтобы избежать deadlock .

146
shallowThought

В 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, вы можете использовать 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
}
20
Usman Javed

Использовать группу рассылки 

   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
Sahil Arora

Swift 4

Вы можете использовать асинхронную функцию для этих ситуаций. Когда вы используете DispatchGroup(), иногда может возникать deadlock .

var a: Int?
@objc func myFunction(completion:@escaping (Bool) -> () ) {

    DispatchQueue.main.async {
        let b: Int = 3
        a = b
        completion(true)
    }

}

override func viewDidLoad() {
    super.viewDidLoad()

    myFunction { (status) in
        if status {
            print(self.a!)
        }
    }
}
0
codeByThey