Работа с несколькими обработчиками завершения

Я пытаюсь согласовать несколько обработчиков завершения для каждого элемента в массиве.

Код по сути такой:

var results = [String:Int]()

func requestData(for identifiers: [String])
{
    identifiers.forEach
    {   identifier in

        service.request(identifier, completion: { (result) in
            result[identifier] = result
        })
    }

    // Execute after all the completion handlers finish
    print(result)
}

Таким образом, каждый элемент в массиве отправляется через службу с обработчиком завершения, и все результаты сохраняются в массиве. После завершения всех этих обработчиков я хочу выполнить некоторый код.

Я пытался сделать это с DispatchQueue

var results = [String:Int]()

func requestData(for identifiers: [String])
{
    let queue = DispatchQueue.init(label: "queue")

    identifiers.forEach
    {   identifier in

        service.request(identifier, completion: { (result) in
            queue.sync
            {
                result[identifier] = result
            }
        })
    }

    // Execute after all the completion handlers finish
    queue.sync
    {
        print(result)
    }
}

но вызов печати все еще выполняется первым, с пустым Dictionary

2 ответа

Решение

Если я понимаю, что вы пытаетесь сделать правильно, вы, вероятно, хотите использовать DispatchGroup

Вот пример:

let group = DispatchGroup()

var letters = ["a", "b", "c"]

for letter in letters {
    group.enter()
    Server.doSomething(completion: { [weak self] (result) in
        print("Letter is: \(letter)")
        group.leave()
    })
}

group.notify(queue: .main) {
    print("- done")
}

Это напечатает что-то вроде:

b
c
a
// ^ in some order
- done

Во-первых, обратите внимание, что ваш service.request(...) обрабатывается в асинхронном режиме. Другая проблема заключается в том, что вы хотите завершить все запросы на обслуживание в этом цикле.

Я предлагаю создать функцию с обработчиком завершения и добавить счетчик для каждого выполненного цикла. Ваша функция будет аналогична приведенной ниже.

var results = [String:Int]()

func requestData(for identifiers: [String], callback:@escaping (Bool) -> Void)
{
    var counter = 0
    var maxItem = identifiers.count

    identifiers.forEach
    {   identifier in

        service.request(identifier, completion: { (result) in
            result[identifier] = result
            counter += 1
            if counter == maxItem {
                callback(true) // update completion handler to say all loops request are done
            }
            // if not, continue the other request
        })
    }
}

Вот как другая часть вашего кода будет вызывать функцию и ждать обратного вызова

requestData(for identifiers:yourArrays) { (complete) in

    if complete {
        print(results)
    }
}

Не забывайте управлять, если произошли ошибки.

Другие вопросы по тегам