Использование обработки исключений по сравнению с NSError в приложениях какао

Эй все. Я читал на предложениях Apple для when/where/how для использования NSError по сравнению с @try / выгода / наконец. По существу мое впечатление - то, что Apple думает, что это лучше всего избегает, чтобы использование языка обработки исключений создало за исключением механизма для останавливающегося выполнения программы в неожиданных ошибочных ситуациях (возможно, кто-то мог дать пример такой ситуации?)

Я происхожу из Java, где исключениями является способ пойти, когда каждый хочет обработать ошибки. По общему признанию я нахожусь все еще в Java thoughtspace, но я медленно борюсь со всем, что должен предложить NSError.

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

Вот пример, который я приготовил, который точно отражает ситуации, с которыми я встречался. Используя некоторые структуры мнимых данных, функция открывает дескриптор файла и создает объект 'MyFileRefInfo', который содержит информацию о том, что сделать с файлом. Некоторый материал сделан с файлом, прежде чем дескриптор файла будет закрыт, и память для структуры освобождена. Используя предложения Apple у меня есть этот метод:

- (BOOL)doSomeThingsWithFile:(NSURL *)filePath error:(NSError **)error
{
  MyFileReference inFile; // Lets say this is a CF struct that opens a file reference
  MyFileRefInfo *fileInfo = new MyFileRefInfo(...some init parameters...);

  OSStatus err = OpenFileReference((CFURLRef)filePath ,&inFile);

  if(err != NoErr)
  {
    *error = [NSError errorWithDomain:@"myDomain" code:99 userInfo:nil];
    delete fileInfo;
    return NO;
  }

  err = DoSomeStuffWithTheFileAndInfo(inFile,fileInfo);

  if(err != NoErr)
  {
    *error = [NSError errorWithDomain:@"myDomain" code:100 userInfo:nil];
    CloseFileHandle(inFile); // if we don't do this bad things happen
    delete fileInfo;
    return NO;
  }      

  err = DoSomeOtherStuffWithTheFile(inFile,fileInfo);

  if(err != NoErr)
  {
    *error = [NSError errorWithDomain:@"myDomain" code:101 userInfo:nil];
    CloseFileHandle(inFile); // if we don't do this bad things happen
    delete fileInfo;
    return NO;
  }      

  CloseFileHandle(inFile);
  delete fileInfo;
  return YES;

}

Теперь.. моя логика Java говорит мне, что было бы лучше настроить это как структуру попытки/выгоды/наконец и поместить все вызовы для окружения дескриптора файла и свободной памяти наконец блок.

Как так..

    ...

    @try
    {
      OSStatus err = OpenFileReference((CFURLRef)filePath ,&inFile);
      if(err != NoErr)
      {
        ... throw some exception complete with error code and description ...
      }

      err = DoSomeStuffWithTheFileAndInfo(inFile,fileInfo);

      if(err != NoErr)
      {
         ... throw some exception ...
      }

      ... etc ...        
}
@catch(MyException *ex)
{
        *error = [NSError errorWithDomain:@"myDomain" code:[ex errorCode] userInfo:nil];
        return NO;
}
@finally
{
        CloseFileHandle(inFile); // if we don't do this bad things happen
        delete fileInfo;
}
return YES;

Действительно ли я являюсь сумасшедшим в размышлении, что это - намного более изящное решение с меньшим количеством избыточного кода? Я пропускал что-то?

11
задан Chris Hanson 7 January 2010 в 00:27
поделиться

4 ответа

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

Это не совсем мое впечатление. Мне показалось, что Apple предлагает использовать исключения для действительно исключительных условий, а NSError - для ожидаемых сбоев. Так как вы пришли из Java, я думаю, NSError -> java.lang.Exception, и Obj-C Exceptions -> java.lang.RuntimeException. Используйте исключение Obj-C, когда программист сделал что-то не так (неправильно использовал API, например), и используйте NSError, когда произошёл ожидаемый сбой (удалённый сервер не был найден, например).

Конечно, это только моя интерпретация позиции Apple. А я, с другой стороны, люблю исключения!

12
ответ дан 3 December 2019 в 02:10
поделиться
[

]Ответ Даниила правильный, но этот вопрос заслуживает более откровенного ответа.[

] [

]Выбрасывайте исключение только при обнаружении неустранимой ошибки.[

] [

]Используйте NSError при сообщении условий ошибки, из которых может быть восстановлена ошибка. [

] [

][][]Любое исключение, которое бросается через кадр в фреймворках Apple, может привести к неопределенному поведению.[][][

] [

]В центре разработки доступен документ []Исключения по теме программирования [].[

].
17
ответ дан 3 December 2019 в 02:10
поделиться
[

] Исключения в Цели-С исторически были "тяжелыми": стоимость входа в пробный блок, стоимость броска, стоимость использования, наконец, и т.д. В результате разработчики Cocoa обычно избегают исключений за пределами ситуаций 'о нет, небо падает' - если файл отсутствует, используйте NSError, но если нет файловой системы и отрицательного объема свободной памяти, то это исключение.[

]. [

] Таков исторический вид. Но если вы собираете 64-битное приложение на 10.5 или более новых версиях, то архитектура исключений была переписана как "нулевая стоимость", что может означать, что исторический вид больше не актуален. Как и в любом случае, все сводится к различным факторам - если работа одним способом более естественна для вас и позволит быстрее закончить, и если вы не испытываете с ней проблем, связанных с производительностью, и если вас не беспокоит небольшое несоответствие с 'традиционным' кодом Objective-C... то нет никаких причин не использовать исключения.[

].
3
ответ дан 3 December 2019 в 02:10
поделиться

Согласно More iPhone 3 Development Дэйва Марка и Джеффа ЛеМарша, исключения используются только в действительно исключительных ситуациях и обычно указывают на проблему в вашем коде. Никогда не следует использовать исключения для сообщения об обычных условиях ошибки. В Objective-C исключения используются гораздо реже, чем во многих других языках, таких как Java и C ++.

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

Вот пример, в котором вы могли бы использовать исключение:

Мы пишем суперкласс, и мы хотим убедиться, что его подклассы реализуют данный метод. Objective-C не имеет абстрактных классов, и ему не хватает механизма, чтобы заставить подкласс реализовать данный метод. Тем не менее, мы можем использовать исключение, чтобы немедленно сообщить нам, что мы забыли реализовать метод в подклассе. Вместо непредсказуемого поведения мы получим исключение во время выполнения. Мы можем легко отладить его, потому что наше исключение точно скажет нам, что мы сделали не так:

NSException *ex = [NSException exceptionWithName:@"Abstract Method Not Overridden" reason:NSLocalizedString(@"You MUST override the save method", @"You MUST override the save method") userInfo:nil];
[ex raise];

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

2
ответ дан 3 December 2019 в 02:10
поделиться
Другие вопросы по тегам:

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