Диспетчерская группа: for-loop * и * асинхронные вызовы внутри цикла for

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

let group = DispatchGroup()

for ref in self.notifsRefList {
    group.enter()
    self.db.fetch(withRecordID: ref.recordID) { notifRecord, notifErr in
        print("async call")
        if notifErr == nil {

            // do stuff

            if let ref = notifRecord?.object(forKey: POST) as! CKReference? {
                group.enter()
                self.db.fetch(withRecordID: ref.recordID) { postRecord, err in
                    print("async call")
                    if err == nil {
                        // do stuff
                        group.leave()
                    }
                    else {
                        print("\(err)")
                        group.leave()
                    }
                }
            }
            if let ref = notifRecord?.object(forKey: USER_NOTIF) as! CKReference? {
                self.db.fetch(withRecordID: ref.recordID) { userRecord, err2 in
                    group.enter()
                    print("async call")
                    if err2 == nil {
                        // do stuff
                        group.leave()
                    }
                    else {
                        print("\(err2)")
                        group.leave()
                    }
                }
            }
            if let ref = notifRecord?.object(forKey: LIBRARY_ITEM) as! CKReference? {
                self.db.fetch(withRecordID: ref.recordID) { libRecord, err3 in
                    group.enter()
                    print("async call")
                    if err3 == nil {
                        // do stuff                        
                        group.leave()
                    }
                    else {
                        print("\(err3)")
                        group.leave()
                    }
                }
            }

            group.leave()

        }
        else {
            print("\(notifErr)")
            group.leave()
        }
    }

}


group.notify(queue: .main, execute: { // executed after all async calls in for loop finish
    print("done with all async calls")
    // do stuff
})

Из операторов печати, которые я включил, я знаю, что мои асинхронные вызовы неверны: иногда "сделано со всеми асинхронными вызовами" печатает перед всеми экземплярами "асинхронного вызова". Буду очень признателен за любую помощь в правильной работе этой диспетчерской группы. Спасибо!

1 ответ

Решение

Проблема в 2-м и 3-м внутренних асинхронных вызовах. Ты звонишь group.enter() внутри блоков завершения, а не перед асинхронными вызовами.

Там также не нужно так много звонков leave,

Вам нужно переместить два следующим образом:

let group = DispatchGroup()

for ref in self.notifsRefList {
    group.enter()
    self.db.fetch(withRecordID: ref.recordID) { notifRecord, notifErr in
        print("async call")
        if notifErr == nil {

            // do stuff

            if let ref = notifRecord?.object(forKey: POST) as! CKReference? {
                group.enter()
                self.db.fetch(withRecordID: ref.recordID) { postRecord, err in
                    print("async call")
                    if err == nil {
                        // do stuff
                    }
                    else {
                        print("\(err)")
                    }
                    group.leave()
                }
            }
            if let ref = notifRecord?.object(forKey: USER_NOTIF) as! CKReference? {
                group.enter()
                self.db.fetch(withRecordID: ref.recordID) { userRecord, err2 in
                    print("async call")
                    if err2 == nil {
                        // do stuff
                    }
                    else {
                        print("\(err2)")
                    }
                    group.leave()
                }
            }
            if let ref = notifRecord?.object(forKey: LIBRARY_ITEM) as! CKReference? {
                group.enter()
                self.db.fetch(withRecordID: ref.recordID) { libRecord, err3 in
                    print("async call")
                    if err3 == nil {
                        // do stuff                        
                    }
                    else {
                        print("\(err3)")
                    }
                    group.leave()
                }
            }
        }
        else {
            print("\(notifErr)")
        }
        group.leave()
    }
}

group.notify(queue: .main, execute: { // executed after all async calls in for loop finish
    print("done with all async calls")
    // do stuff
})
Другие вопросы по тегам