Обработка DispatchGroup [слабая самооценка] во вложенном уведомлении

У меня две асинхронные функции. Мне нужно запустить вторую функцию на основе первого вывода и запустить третью функцию после завершения второй. Я сделал это вот так. Это правильный способ сериализации? И как справиться со слабой ссылкой на себя?

let dispatchGroup = DispatchGroup()

dispatchGroup.enter()
function1() // async completion contains leave()

dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
    guard let strongSelf = self else {return}
    strongSelf.dispatchGroup.enter()    
    strongSelf.function2() // Also async, dependent on the result of function1. contains leave()

    strongSelf.dispatchGroup.notify(queue: DispatchQueue.main) {
        strongSelf????.function3()
        print("results of function1 and function2")
        // I must wait to finish first two tasks in order, in other words serial queue
    }
}

person Jim H.    schedule 05.08.2017    source источник


Ответы (2)


1) Правильный способ: вызвать метод после завершения предыдущего.

class SomeAsyncType {

    typealias SomeResultType = String

    func async(_ someDate: Any, completion: @escaping (SomeResultType) -> Void) {
        self.asyncfunctionA(someDate, completion: completion)
    }

    private func asyncfunctionA(_ someDate: Any, completion: @escaping (SomeResultType) -> Void) {
        DispatchQueue.main.async { [weak self] in
            sleep(1)
            print("ResultA")
            self?.asyncfunctionB("ResultA", completion: completion)
        }
    }

    private func asyncfunctionB(_ someDate: Any, completion: @escaping (SomeResultType) -> Void) {
        DispatchQueue.main.async { [weak self] in
            sleep(2)
            print("ResultB")
            self?.asyncfunctionC("ResultB", completion: completion)
        }
    }

    private func asyncfunctionC(_ someDate: Any, completion: @escaping (SomeResultType) -> Void) {
       DispatchQueue.main.async {
            sleep(3)
            print("ResultC")
            completion("????????????")
            print("All completed")
        }
    }
}

использование:

let test = SomeAsyncType() // hold reference 
test.async("noDate") { result in
    print(result)
}

консоль:

ResultA
ResultB
ResultC
????????????
All completed

2) как справиться со слабой ссылкой на себя?

Это новая область действия, вы можете снова использовать [weak self]

dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
    guard let strongSelf = self else {return}
    strongSelf.dispatchGroup.enter()
    strongSelf.function2() // Also async, dependent on the result of function1. contains leave()

    strongSelf.dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
        guard let strongSelf = self else {return}
        strongSelf.function3()
        print("results of function1 and function2")
    }
}
person Adrian Bobrowski    schedule 05.08.2017
comment
Я так и думал. Это правильный способ обработки асинхронных функций? Я хочу, чтобы вызовы функций были отдельными, например, чтобы функция reverseGeocode возвращалась отдельно, прежде чем я начну вызов следующей функции для использования результата гео. А когда завершится второй вызов, запустите третий, чтобы просто распечатать результаты. Как этого добиться? Я пробовал последовательную синхронизацию / асинхронность DispatchQueue, но во всех случаях reverseGeo возвращает результат на последнем - person Jim H.; 05.08.2017
comment
Спасибо за объяснение. Можно ли это сделать без обработчика завершения? Например, serialQueue.sync / async {function1}, serialQueue.sync / async {function2}, serialQueue.sync / async {function3}? По-прежнему результат function1 с reverseGeocode приходит последним. DispatchQueue сбивает с толку. - person Jim H.; 06.08.2017
comment
@JimH. Посмотрите мой другой ответ stackoverflow.com/a/45475347/6756852 - person Adrian Bobrowski; 06.08.2017

Это зависит от того, какие у вас функции 1 и 2, но я бы подумал о том, чтобы сделать это с CompleteHandlerInstead:

function1(completionHandler: { [weak self] results in
   guard let strongSelf = self else {return} 

   if results == true //if it'd be bool
   {
      strongSelf.function2(completionHandler: { [weak self] results in
   guard let strongSelf = self else {return}

      //here you can get results from both if you want
      })
   }
   else
   {
   //false
   }
})
person Kam Wo    schedule 05.08.2017
comment
с обработчиком завершения я могу поместить вторую функцию в завершение первой, а третью - в завершение за секунды, чтобы вообще избежать DispatchGroup. Я хотел, чтобы вызовы функций были раздельными, например, чтобы функция reverseGeocode возвращалась отдельно, прежде чем я начну вызов следующей функции для использования результата гео. А когда будет выполнен второй вызов, запустите третий, чтобы просто распечатать результаты. Как этого добиться? Я пробовал использовать последовательную синхронизацию / асинхронность DispatchQueue, но во всех случаях reverseGeo возвращает результат в последнюю очередь. - person Jim H.; 05.08.2017
comment
serialQueue.sync {function1}, serialQueue.sync {function2}, serialQueue.sync {function3}, По-прежнему результат function1 с reverseGeocode приходит последним - person Jim H.; 05.08.2017