Эй все. Я читал на предложениях 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;
Действительно ли я являюсь сумасшедшим в размышлении, что это - намного более изящное решение с меньшим количеством избыточного кода? Я пропускал что-то?
По сути, у меня сложилось впечатление, что Apple считает, что лучше избегать использования конструкций языка обработки исключений, кроме как в качестве механизма остановки выполнения программы в непредвиденных ошибочных ситуациях (может быть, кто-нибудь может привести пример такой ситуации?)
Это не совсем мое впечатление. Мне показалось, что Apple предлагает использовать исключения для действительно исключительных условий, а NSError - для ожидаемых сбоев. Так как вы пришли из Java, я думаю, NSError -> java.lang.Exception, и Obj-C Exceptions -> java.lang.RuntimeException. Используйте исключение Obj-C, когда программист сделал что-то не так (неправильно использовал API, например), и используйте NSError, когда произошёл ожидаемый сбой (удалённый сервер не был найден, например).
Конечно, это только моя интерпретация позиции Apple. А я, с другой стороны, люблю исключения!
]Ответ Даниила правильный, но этот вопрос заслуживает более откровенного ответа.[
] []Выбрасывайте исключение только при обнаружении неустранимой ошибки.[
] []Используйте NSError при сообщении условий ошибки, из которых может быть восстановлена ошибка. [
] [][][]Любое исключение, которое бросается через кадр в фреймворках Apple, может привести к неопределенному поведению.[][][
] []В центре разработки доступен документ []Исключения по теме программирования [].[
].] Исключения в Цели-С исторически были "тяжелыми": стоимость входа в пробный блок, стоимость броска, стоимость использования, наконец, и т.д. В результате разработчики Cocoa обычно избегают исключений за пределами ситуаций 'о нет, небо падает' - если файл отсутствует, используйте NSError, но если нет файловой системы и отрицательного объема свободной памяти, то это исключение.[
]. [] Таков исторический вид. Но если вы собираете 64-битное приложение на 10.5 или более новых версиях, то архитектура исключений была переписана как "нулевая стоимость", что может означать, что исторический вид больше не актуален. Как и в любом случае, все сводится к различным факторам - если работа одним способом более естественна для вас и позволит быстрее закончить, и если вы не испытываете с ней проблем, связанных с производительностью, и если вас не беспокоит небольшое несоответствие с 'традиционным' кодом Objective-C... то нет никаких причин не использовать исключения.[
]. Согласно 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];
Поскольку проблема - это ошибка программиста, а не проблема, которую пользователь может исправить, мы используем исключение.