Я использую приведенный ниже код, чтобы дождаться завершения асинхронных задач. Пару раз работает и вылетает. 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, прежде чем продолжить?
Это интерактивное приложение командной строки, поэтому пользователь ждет результата.
Это не меняет того факта, что вы должны правильно работать с асинхронными вызовами.
В синхронном режиме основная функция принимает строковый вызов процесса, который выполняет связку функций и возвращает результат. Если процесс асинхронный, он возвращается, и результат недоступен пользователю.
Вы не можете разыменовывать ивары с помощью ->
, если 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
, и она не равна нулю.
Похоже, сбой из-за асинхронной отправки исправлен с помощью локальной группы отправки var и проверки количества обратных вызовов.
Было бы лучше, если бы вы не пытались преобразовать асинхронный вызов в синхронный вызов. Измените
process
, чтобы использовать обработчик завершения вместо прямого возврата значения.