Как предотвратить сбой группы рассылки?

Я использую приведенный ниже код, чтобы дождаться завершения асинхронных задач. Пару раз работает и вылетает. updateFromTable всегда вызывает callback(), чтобы групповые вызовы были сбалансированы, но все равно падает.

- (void)updateFromTable:(Table *)table env:(Env *)env callback:(void (^)(void))callback {
    [someasync usingBlock:^{
        callback()
    }];
}

- (NSString * _Nullable)process {
    JSL * __weak weakSelf = self;
    NSString __block *ret = nil;
    dispatch_group_enter(_dispatchGroup);
    dispatch_async(_repQueue, ^{
        JSL *this = weakSelf;
        [this updateFromTable:[this->_env table] env:this->_env callback:^{
            ret = [some op .. ];
            dispatch_group_leave(this->_dispatchGroup);
        }];
    });
    dispatch_group_wait(_dispatchGroup, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC));
    info(@"%@", @"done");
    return ret;
}

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


Ссылка: Как дождаться прохождения dispatch_async, прежде чем продолжить?

Было бы лучше, если бы вы не пытались преобразовать асинхронный вызов в синхронный вызов. Измените process, чтобы использовать обработчик завершения вместо прямого возврата значения.

rmaddy 26.05.2019 17:55

Это интерактивное приложение командной строки, поэтому пользователь ждет результата.

johndoe 26.05.2019 17:59

Это не меняет того факта, что вы должны правильно работать с асинхронными вызовами.

rmaddy 26.05.2019 18:01

В синхронном режиме основная функция принимает строковый вызов процесса, который выполняет связку функций и возвращает результат. Если процесс асинхронный, он возвращается, и результат недоступен пользователю.

johndoe 26.05.2019 18:04
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
194
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы не можете разыменовывать ивары с помощью ->, если this является nil. Таким образом, типичным решением является создание сильной ссылки, которая не может быть освобождена во время выполнения замыкания, и return, если это nil:

- (NSString * _Nullable)process {
    typeof(self) __weak weakSelf = self;
    [self asynchronousMethodWithCompletion:^{
        typeof(self) strongSelf = weakSelf;
        if (!strongSelf) { return; }

        // can now safely use `strongSelf` here
    });

    ...
}

Это «weakSelf-strongSelf танец». Вы используете его в ситуациях, когда вам нужно убедиться, что self не является nil, когда вы его используете, например. разыменование иваров (strongSelf->ivar) .

Таким образом:

- (NSString * _Nullable)process {
    typeof(self) __weak weakSelf = self;
    NSString __block *ret = nil;
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    dispatch_async(_repQueue, ^{
        typeof(self) strongSelf = weakSelf;
        if (!strongSelf) { return; }

        [strongSelf updateFromTable:[strongSelf->_env table] env:strongSelf->_env callback:^{
            ret = [some op .. ];
            dispatch_group_leave(group);
        }];
    });
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    info(@"%@", @"done");
    return ret;
}

Несколько других наблюдений:

  • Группа отправки должна быть локальной переменной метода, а не ivar. В вашем коде нет необходимости ссылаться на это group.

  • Убедитесь, что ваши dispatch_group_leave вызовы не превышают количество dispatch_group_enter вызовов (т. е. этот блок обработчика завершения не вызывается несколько раз).

  • Я бы посоветовал дождаться DISPATCH_TIME_FOREVER (при условии, что вы действительно хотите дождаться его завершения).

  • Кроме того, если это свойства (которые, как я предполагаю, основаны на знаках подчеркивания), то использование self.env вместо self->_env безопаснее, так как это не приведет к сбою, если self равно nil, а просто вернет nil.

Должен признаться, что это все еще выглядит неправильно (например, если updateFromTable уже асинхронно, зачем асинхронно отправлять это в _repQueue; если синхронно, то опять же, зачем асинхронно отправлять это только для того, чтобы дождаться его). Но невозможно комментировать дальше, не видя реализации updateFromTable.


Или, лучше, сделать метод асинхронным:

- (void)processWithCompletion:(void (^)(NSString *))callback {
    typeof(self) __weak weakSelf = self;
    dispatch_async(_repQueue, ^{
        typeof(self) strongSelf = weakSelf;
        if (!strongSelf) { return; }

        [strongSelf updateFromTable:[strongSelf->_env table] env:strongSelf->_env callback:^{
            NSString *ret = [some op .. ];
            callback(ret);
        }];
    });
}

Я проверил переменную this, и она не равна нулю.

johndoe 26.05.2019 17:57

Похоже, сбой из-за асинхронной отправки исправлен с помощью локальной группы отправки var и проверки количества обратных вызовов.

johndoe 26.05.2019 18:19

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