Вернитесь внутрь просто попробуйте [закрыто]

Расширение на Jörn Eyrich отвечает (повышайте его ответ, если вы продвигаете этот вариант), если у вас нет контроля над вызовами dispatch_async для ваших блоков, как это может быть в случае блоков завершения асинхронизации, вы можете использовать GCD группы, использующие dispatch_group_enter и dispatch_group_leave.

В этом примере мы притворяемся, что computeInBackground - это то, что мы не можем изменить (представьте, что это обратный вызов делегата, NSURLConnection completeHandler или что-то еще) и таким образом, у нас нет доступа к вызовам отправки.

// create a group
dispatch_group_t group = dispatch_group_create();

// pair a dispatch_group_enter for each dispatch_group_leave
dispatch_group_enter(group);     // pair 1 enter
[self computeInBackground:1 completion:^{
    NSLog(@"1 done");
    dispatch_group_leave(group); // pair 1 leave
}];

// again... (and again...)
dispatch_group_enter(group);     // pair 2 enter
[self computeInBackground:2 completion:^{
    NSLog(@"2 done");
    dispatch_group_leave(group); // pair 2 leave
}];

// Next, setup the code to execute after all the paired enter/leave calls.
//
// Option 1: Get a notification on a block that will be scheduled on the specified queue:
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    NSLog(@"finally!");
});

// Option 2: Block an wait for the calls to complete in code already running
// (as cbartel points out, be careful with running this on the main/UI queue!):
//
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // blocks current thread
// NSLog(@"finally!");

В этом примере computeInBackground: завершение: реализовано как:

- (void)computeInBackground:(int)no completion:(void (^)(void))block {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSLog(@"%d starting", no);
        sleep(no*2);
        block();
    });
}

Выход (с отметками времени от run):

12:57:02.574  2 starting
12:57:02.574  1 starting
12:57:04.590  1 done
12:57:06.590  2 done
12:57:06.591  finally!
4
задан Keivan Ameri 9 March 2019 в 16:09
поделиться

2 ответа

Самое главное, чтобы ваш абонент получил информацию о том, что вызов createUnit() не удался. Вы уже сказали, что null - плохой выбор для этого, и я полностью согласен.

Лучший способ - создать исключение для вашего абонента, но какое именно?

  • Оригинальное?

  • Или вновь -created one?

Какие аспекты мы должны рассмотреть?

  • Читаемость кода ухудшается, если вы загромождаете свой код (непродуктивными) строками обработки ошибок. Вместо этого вы должны сосредоточиться на том, что вы действительно хотите сделать - это достаточно сложно. Поэтому любые попытки / ловли / броски, которых вы можете избежать, не жертвуя надежностью, должны быть удалены.
  • Вашему звонящему нужна информация о том, что вызов не удался, и именно для этого предназначены исключения, поэтому он должен получить его.
  • Одна проблема должна регистрироваться только один раз, на каком-то верхнем уровне или на границах обслуживания. Для этого исключение должно содержать информацию для последующего анализа проблемы. Системные исключения Java уже содержат много полезной информации, но иногда вы хотите добавить больше контекстной информации. Не должно быть необходимости регистрировать ошибки на более низких уровнях.
  • Будет ли вызывающий абонент писать код, который зависит от типа исключения, то есть блоков try / catch с разными реакциями для разных типов исключений? Может ли он даже сделать это? Может / должен ли он понять внутреннюю работу вашего метода достаточно хорошо, чтобы знать, что делать в том или ином случае исключения? Обычно нет. Таким образом, класс исключений обычно не имеет значения.
  • Как приложение в конечном итоге сообщит своему пользователю, что какая-то функция не сработала? Может ли ваше исключение помочь с этой задачей, например, предоставив соответствующее сообщение? Но знаете ли вы, какая формулировка может подойти для вашего абонента? Поэтому я сомневаюсь, что вы можете быть здесь полезны.

Итак, единственная причина, по которой я вижу обертку исключения более низкого уровня, в то, что вы хотите добавить контекстную информацию, полезную для ведения журнала (или если какая-то сигнатура фиксированного метода вынуждает вас переводить оригинальное исключение).

0
ответ дан Ralf Kleberhoff 9 March 2019 в 16:09
поделиться

Создайте новый соответствующий Exception, который может управлять пользовательскими данными, такими как значение ввода unitLevel.

public class UnitCreationException extends Exception {
   ...

   // Package-private constructor.
   // Don't expose too much to the outer world
   UnitCreationException(
        final String message,
        final int unitLevel,
        final Throwable cause) { ... }
}

Поймайте Exception на месте, записав, что, по вашему мнению, может оказаться полезной информацией, доступ к которой можно получить только в этот момент

public Unit createUnit(final int unitLevel) throws UnitCreationException {
    final List<String> widgetClassNames = getUnitsClasses();

    try {
        return (Unit) Class.forName(widgetClassNames.get(unitLevel))
                           .getConstructor(Player.class)
                           .newInstance(getOwner().get());
    } catch (InstantiationException 
            | IllegalAccessException 
            | IllegalArgumentException 
            | InvocationTargetException
            | NoSuchMethodException 
            | SecurityException 
            | ClassNotFoundException e) {
        // Do not log the Exception stack-trace here, you'll do that
        // at a hihger level
        logger.error("Error message");

        // Re-throw your custom and more meaningful Exception
        throw new UnitCreationException("Error message", unitLevel, e);
    }
}

На более высоком уровне вы будете вынуждены чтобы понять, что UnitCreationException

try {
   final Unit unit = createUnit(10);
} catch (final UnitCreationException e) {
   // Here you can log the Exception stack-trace
   logger.error("Error message", e);

   // Do something with the information contained in the custom Exception
   final int erroredUnitLevel = e.getUnitLevel();
   ...
}

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

Вы хотели бы иметь возможность каким-то образом восстановиться после такой ошибки, не останавливая все приложение (возможно, с помощью логики повторной попытки).


Я был свидетелем того, как разработчики использовали Optional<T> в качестве возвращаемого типа, только чтобы избежать null. Это контрпродуктивно , так как вы теряете действительную причину ошибки, и вы не можете отреагировать на это в своей собственной ветви (ветка catch)

В конечном счете, Java предлагает вам способ настройки Exception, так что используйте эту функцию.

0
ответ дан LppEdd 9 March 2019 в 16:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: