Изменение массива из асинхронного вызова без изменения массива Swift

Я пытаюсь изменить массив объектов, которые я извлекаю из асинхронного вызова, с результатами другого асинхронного вызова. В основном я получаю массив результатов, и есть поле messages, которое возвращает nil из моего вызова сервера. Затем мне нужно сделать еще один вызов сервера с я бы каждого result в цикле for, чтобы получить массив messages. Затем я устанавливаю messages на возвращаемое значение.

Я только что узнал об использовании ДиспетчерГрупп() около 20 минут назад от https://stackoverflow.com/a/48718976/3272438, так что терпите меня.

Проблема, которую я получаю, заключается в том, что когда я делаю print("C0: (собственное.разрешение)"), он распечатывает все элементы, включая только что добавленный messages. Когда print("C2: (собственное.разрешение)") печатается в group.notify(...), все поля messages выводят ноль. Я в тупике, и я перепробовал все, что мог придумать. Любая помощь приветствуется.

ОБНОВИТЬ При изменении следующего group.notify() никогда не вызывается

Service.getMessages(resultId: self.res![index].id, completionHandler: { (latestMessage, response, error) in

        if let latestMessage = latestMessage {
            self.res![index].messages = [latestMessage]
            print("L2: \(self.res![index].messages)")
            print("C0: \(self.res)")
        }
        group.leave() // continue the loop
    })

ViewController.Swift

var res: [ResultDTO]?

override func viewDidLoad() {
    super.viewDidLoad()

    let group0 = DispatchGroup()

    group0.enter()
    Service.getResults { (results, response, error) in
        guard var results = results else { print("PROBLEM"); return }
        self.res = results
        group0.leave()
    }

    group0.notify(queue: .main) {
        print("in group0")
        let group = DispatchGroup() // initialize
        for index in 0..<self.res!.count {
            group.enter() // wait
            Service.getMessages(resultId: self.res![index].id, completionHandler: { (latestMessage, response, error) in

                if let latestMessage = latestMessage {
                    self.res![index].messages = [latestMessage]
                    print("L2: \(self.res![index].messages)")
                    print("C0: \(self.res)")
                }

            })
            group.leave() // continue the loop
        }

        group.notify(queue: .main) {
            print("In group notify")

            do {
                print("C2: \(self.res)")
                for index in 0..< self.res!.count {
                    print("L4: \(self.res![index].messages)")
                }
                // ... configure my view with the data
            } catch {
                print("Error: \(error)")
            }

        }
    }

}

Кстати, уродливая архитектура базы данных, верно? Можно ли исправить архитектуру данных вместо того, чтобы прыгать через эти обручи на клиенте?

liquid LFG UKRAINE 30.05.2019 01:20

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

nviens 30.05.2019 01:25

Какая у вас настройка базы данных? Бессерверный NoSQL?

liquid LFG UKRAINE 30.05.2019 01:26

Использование базы данных Oracle и бэкенда Java с Hibernate.

nviens 30.05.2019 01:27

У меня нет опыта работы с базами данных Oracle, поэтому я не знаю, как лучше всего их использовать. На вашем месте я бы потратил время на выяснение того, как упростить сбор данных. Можно ли сократить его до одного сетевого звонка? Почему не решаются денормализовать эти данные?

liquid LFG UKRAINE 30.05.2019 01:34

Мне нужно будет немного спланировать, как упростить поиск данных. Именно так мы его разработали, вместо того, чтобы возвращать все данные сразу, когда они не нужны, просто возвращать необходимые фрагменты информации. Код. Я попытался переместить его, но он не вводит group.notify() и не печатает In group notify.

nviens 30.05.2019 01:42

Покажите, пожалуйста, определение getMessages. Описанное поведение предполагает, что ваш getMessages не закодирован должным образом.

OOPer 30.05.2019 03:02
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
7
165
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я бы упростил обработку ваших данных, используя одну группу диспетчеризации (поскольку вам нужна только одна):

class YourViewController: UIViewController {

    private var results: [ResultDTO]?

    override func viewDidLoad() {
        super.viewDidLoad()
        getResults()
    }

    private func getResults() {

        Service.getResults { (results, response, error) in

            guard let results = results,
                results.count > 0 else {
                    return
            }

            let dispatchGroup = DispatchGroup()

            for r in results {

                dispatchGroup.enter()
                Service.getMessages(resultId: r.id, completionHandler: { (latestMessage, response, error) in

                    if let latestMessage = latestMessage {
                        r.messages = [latestMessage]
                    }
                    dispatchGroup.leave()

                }

            }

            dispatchGroup.notify(queue: .main, execute: {
                self.results = results
            })

        }

    }

}

Считайте это только отправной точкой. Если бы это был производственный код, я бы реализовал обработку ошибок и фоновую очередь (при условии, что данные возвращаются в основном потоке).

Пытаюсь реализовать и получаю следующую ошибку: Incorrect argument label in call (have 'queue:execute:', expected 'queue:work:') with dispatchGroup.notify(...)

nviens 30.05.2019 02:04

Вы используете notify(queue: DispatchQueue, work: DispatchWorkItem), когда вы должны использовать notify(queue: DispatchQueue, execute: () -> Void)

liquid LFG UKRAINE 30.05.2019 02:06

Или просто используйте завершающее замыкание, как вы сделали dispatchGroup.notify(queue: .main) { ... }

liquid LFG UKRAINE 30.05.2019 02:07

Я не уверен, что он попадает в dispatchGroup.notify(...), потому что, если я поставлю print("hello"), ничего не будет напечатано.

nviens 30.05.2019 02:21

Вы все еще не используете несколько групп отправки, не так ли?

liquid LFG UKRAINE 30.05.2019 02:28

Нет, я скопировал и вставил ваш код и получил только одну группу

nviens 30.05.2019 02:30

Каков тип данных results из первого сетевого звонка?

liquid LFG UKRAINE 30.05.2019 02:33

Пользовательская структура resultDTO с { id, messages, timestamp, ... }, и я просто хочу установить поле messages. Если я поставлю операторы печати, они будут напечатаны везде, кроме как внутри dispatchGroup.notify(...)

nviens 30.05.2019 02:38
results — это массив resultDTO, верно? Когда вы печатаете при отправке ввода и отправке отпуска, печатается ли одинаковое количество входов и выходов, и равно ли это количество результатов, возвращенных из первого сетевого вызова?
liquid LFG UKRAINE 30.05.2019 02:42

Да, это массив resultDTO. Начальный размер 20, при входе = 20, при выходе = 6. Я добавил к вашему ответу свои операторы печати. A распечатывает AAA: 0 AAA: 1 AAA: 2 AAA: 3 AAA: 4 AAA: 5 AAA: 6 AAA: 7 AAA: 8 AAA: 9 AAA: 10 AAA: 11 AAA: 12 AAA: 13 AAA: 14 AAA: 15 AAA: 16 AAA: 17 AAA: 18 AAA: 19, а B распечатывает: BBB: 0 BBB: 1 BBB: 6 BBB: 4 BBB: 15 BBB: 18

nviens 30.05.2019 02:48

Пока не повезло... Все еще не попал в notify

nviens 30.05.2019 02:59

Тогда это почти наверняка ваши данные или сервер. Убедитесь, что все данные действительно существуют. Также в Service.getMessages вернитесь, if let error = error { print(error) } и посмотрите, возвращает ли сервер ошибку. Код правильный, и мы знаем, что он работает, потому что он повторяет цикл, совершая нужное количество сетевых вызовов. Он просто не возвращает то же количество результатов, что указывает на ошибку на стороне сервера.

liquid LFG UKRAINE 30.05.2019 03:04

Да, я только что понял, что это, скорее всего, серверная сторона, и я смотрю на это сейчас.

nviens 30.05.2019 03:09

Есть ли причина, по которой вы не используете Google Firestore? Кстати, 20 последовательных обращений к базе данных, возможно, нарушают ограничение сервера, что является еще одной причиной для реструктуризации ваших данных, чтобы ограничить захват данных одним вызовом. Когда сообщения создаются, делайте две записи вместо одной, и тогда вы сможете получить все эти данные за один раз.

liquid LFG UKRAINE 30.05.2019 03:10

Мы только что выбрали собственную реализацию серверной части, а не Google Firebase или Firestore. Просто так все получилось. Да, определенно нужно реструктурировать данные, чтобы их было проще получить, чем несколько вызовов. НО, с другой стороны, я нашел свою проблему. Это случилось в моем вызове API. У меня есть метод автоматического декодирования данных в требуемый тип объекта, и если decode() не удалось, он просто не возвращается. Я добавил обработчик завершения(), и теперь он входит в блок notify, но все еще не имеет messages в объекте.

nviens 30.05.2019 03:28

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