Используя и ошибочные объекты создания

Следующие разделы описывают, как иметь дело с NSError объекты возвратились из методов платформы, как вывести на экран сообщения об ошибках с помощью ошибочных объектов, как создать ошибочные объекты, и как реализовать методы, возвращающие ошибочные объекты ссылкой.

Объекты ошибки из-за неправильного обращения возвратились из методов

Много методов Сенсорных классов Какао и Какао включают как их последний параметр прямую или косвенную ссылку на NSError объект. В некоторой Основе и методах UIKit Вы находите NSError объекты как параметры методов делегации. Следующее объявление от платформы UIKit UIWebViewDelegate протокол; делегат реализовал бы метод, такой как это, чтобы узнать, перестала ли работа работать:

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;

Некоторые методы платформ Какао, которые Вы вызываете, включают косвенную ссылку на NSError объект; эти методы обычно выполняют работу, такую как создание документа, запись файла или загрузка URL. Например, следующее объявление метода от NSDocument заголовочный файл класса:

- (BOOL)writeToURL:(NSURL *)absoluteURL
    ofType:(NSString *)typeName
    error:(NSError **)outError;

Если метод, такой как это встречается с ошибкой в своей реализации, он непосредственно возвращается NO указать отказ и косвенно возвращается (если клиентский код запрашивает его), NSError объект в последнем параметре, который опишет ошибку.

Если Вы хотите оценить ошибку, объявите NSError переменная объекта прежде, чем вызвать метод такой как writeToURL:ofType:error:. Когда Вы вызываете метод, передаете в указателе на эту переменную. (Если Вы не интересуетесь ошибкой, просто передаете NULL.), Если непосредственно возвращается метод nil или NO, проверьте NSError объект определить причину ошибки или просто вывести на экран ошибочное предупреждение. Перечисление 2-1 иллюстрирует этот подход.

Перечисление 2-1  , обрабатывающее NSError объект возвратился из метода AppKit

NSError *theError;
BOOL success = [myDoc writeToURL:[self docURL] ofType:@"html" error:&theError];
 
if (success == NO) {
    // Maybe try to determine cause of error and recover first.
    NSAlert *theAlert = [NSAlert alertWithError:theError];
    [theAlert runModal]; // Ignore return value.
}

Этот код в Перечислении 2-1 использует возвращенный NSError для отображения ошибки сразу предупреждают пользователю. (UIAlertView, соответствие класса UIKit NSAlert, не имеет никакого эквивалентного метода для alertWithError:.) Ошибочные объекты в домене Cocoa всегда локализуются и готовы представить пользователям, таким образом, они могут часто представляться без дальнейшей оценки.

Вместо того, чтобы просто вывести на экран сообщение об ошибке на основе NSError объект, Вы могли исследовать объект определить, можно ли сделать что-то еще. Например, Вы могли бы быть в состоянии выполнить работу снова немного отличающимся способом, обходящим ошибку; если Вы делаете это, однако, необходимо сначала запросить разрешение пользователя выполнить измененную работу.

При оценке NSError объект, всегда используйте домен объекта и код ошибки как основы тестов а не строк, описывающих ошибку или как восстановиться с него. Строки обычно локализуются и вероятно, будут, таким образом варьироваться. За немногим исключением (такой как NSURLErrorDomain домен), существующие ранее ошибки, возвращенные из методов платформы Какао, всегда находятся в NSCocoaErrorDomain домен; однако, потому что существуют исключения, Вы могли бы хотеть протестировать, принадлежит ли ошибка верхнего уровня тому домену. Ошибочные объекты, возвращенные из методов Какао, могут часто содержать базовые ошибочные объекты, представляющие ошибки, возвращенные более низкими подсистемами, такими как уровень BSD (NSPOSIXErrorDomain).

Конечно, для создания успешной оценки ошибки необходимо ожидать ошибки, которые могли бы быть возвращены из вызова метода. И необходимо гарантировать, что код имеет дело соответственно с новыми ошибками, которые могли бы быть возвращены в будущем.

Альтернативы обработки ошибок в OS X

При разработке приложения Mac существует много других вещей, которые можно сделать после получения NSError объект:

  • Если Вы знаете, как восстановиться с ошибки, но потребовать утверждения пользователя, Вы могли создать новую версию ошибочного объекта, добавляющего восстановление attempter к нему (см. Восстановление С Ошибок).

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

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

  • Если Вы используете возвращенный NSError возразите как основание нового ошибочного объекта, или путем добавления восстановления attempter или дополнительной информации, Вы можете также:

    • Выведите на экран сообщение сразу.

    • Передайте ошибку следующему ошибочному респонденту.

    Для больше при настройке ошибок отказался от цепочки ошибочного респондента, посмотрите Обработку Полученные Ошибки.

Отображение информации от ошибочных объектов

Существует несколько различных способов вывести на экран информацию в NSError объекты. Вы могли извлечь локализованное описание (или причина отказа), предложение восстановления, и опции восстановления от ошибки возражают и используют их для инициализации мозаик и текста сообщения NSAlert, UIAlertView, или UIActionSheet объект (или OS X модальный лист документа). Этот универсальный подход дает Вам значительную степень управления содержанием и представления ошибочного предупреждения.

Например, код в Перечислении 2-2 составляет текст сообщения UIAlertView объект из локализованного описания и причины отказа, взятой от переданного - в NSError объект.

Перечисление 2-2  , Выводящее на экран предупреждение, сочинило главным образом от ошибочных атрибутов объектов

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
 
    NSString *titleString = @"Error Loading Page";
    NSString *messageString = [error localizedDescription];
    NSString *moreString = [error localizedFailureReason] ?
                        [error localizedFailureReason] :
                        NSLocalizedString(@"Try typing the URL again.", nil);
    messageString = [NSString stringWithFormat:@"%@. %@", messageString, moreString];
 
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:titleString
        message:messageString delegate:self
        cancelButtonTitle:@"Cancel" otherButtonTitles:nil];
    [alertView show];
}

Однако Вы не должны использовать локализованные строки ошибки, сделанные доступный платформами. Например, если Вы думаете, что они не являются достаточно дескриптивными или хотят дополнить их с зависящей от контекста информацией, можно идентифицировать ошибку ее доменом и кодом и затем заменить собственными строковыми значениями. Возьмите метод делегата, используемый в предшествующем примере; ошибочный объект передал делегату в webView:didFailLoadWithError: имеет почти всегда NSURLErrorDomain домен. Вы могли тогда узнать, какой код этого домена связан с ошибкой, и замените своей собственной строкой строки, содержавшиеся в ошибочном объекте. (NSURLErrorDomain и его коды объявляются в NSURLError.h.) Перечисление 2-3 дает пример этого.

Перечисление 2-3  , Присваивающее пользовательские строки сообщения на основе ошибочного домена и кода

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
 
    NSString *errorMsg;
 
    if ([[error domain] isEqualToString:NSURLErrorDomain]) {
        switch ([error code]) {
            case NSURLErrorCannotFindHost:
                errorMsg = NSLocalizedString(@"Cannot find specified host. Retype URL.", nil);
                break;
            case NSURLErrorCannotConnectToHost:
                errorMsg = NSLocalizedString(@"Cannot connect to specified host. Server may be down.", nil);
                break;
            case NSURLErrorNotConnectedToInternet:
                errorMsg = NSLocalizedString(@"Cannot connect to the internet. Service may not be available.", nil);
                break;
            default:
                errorMsg = [error localizedDescription];
                break;
        }
    } else {
        errorMsg = [error localizedDescription];
    }
 
    UIAlertView *av = [[UIAlertView alloc] initWithTitle:
        NSLocalizedString(@"Error Loading Page", nil)
        message:errorMsg delegate:self
        cancelButtonTitle:@"Cancel" otherButtonTitles:nil];
    [av show];
}

Распространение ошибок для дисплея объектом приложения (OS X)

Набор Приложения обеспечивает несколько ярлыков для отображения ошибочных предупреждений. presentError: и presentError:modalForWindow:delegate:didPresentSelector:contextInfo: методы разрешают Вам порождать ошибочное предупреждение, в конечном счете выведенное на экран глобальным объектом приложения, NSApp; прежний метод запрашивает модальное приложением предупреждение и последнего модальное документом предупреждение. Необходимо отправить любое из этих существующих сообщений об ошибках к объекту в цепочке ошибочного респондента (см. Цепочку Ошибочного респондента): объект представления, объект окна, NSDocument объект, NSWindowController объект, NSDocumentController объект, или NSApp. (При отправке сообщения в представление это должен идеально быть объект представления, связанный в некотором роде с условием, произведшим ошибку.) Перечисление 2-4 иллюстрирует, как Вы могли бы вызвать модальное документом presentError:modalForWindow:delegate:didPresentSelector:contextInfo: метод.

Перечисление 2-4  , Выводящее на экран модальное документом ошибочное предупреждение

NSError *theError;
NSData *theData = [doc dataOfType:@”xml” error:&theError];
if (!theData && theError)
    [anyView presentError:theError
            modalForWindow:[doc windowForSheet]
            delegate:self
            didPresentSelector:
                @selector(didPresentErrorWithRecovery:contextInfo:)
            contextInfo:nil];

После того, как пользователь отклоняет предупреждение, NSApp вызывает метод (идентифицированный в didPresentSelector: ключевое слово) реализованный модальным делегатом. Поскольку Перечисление 2-5 показывает, модальный делегат в этом методе проверяют, управлял ли объект восстановления-attempter (если таковые имеются) восстановиться с ошибки и отвечает соответственно.

Перечисление 2-5  Модальный делегат, обрабатывающий пользовательский ответ

- (void)didPresentErrorWithRecovery:(BOOL)recover contextInfo:(void *)info {
    if (recover == NO) { // Recovery did not succeed, or no recovery attempted.
        // Proceed accordingly.
    }
}

Для больше на объекте восстановления-attempter, посмотрите Восстановление С Ошибок.

Иногда Вы не могли бы хотеть отправлять, ошибка возражают цепочке ошибочного респондента, которая будет выведена на экран NSApp. Вы показали бы ошибочное предупреждение пользователю сразу и не имели бы для построения его сами. NSAlert класс обеспечивает alertWithError: метод с этой целью.

Перечисление 2-6  , Непосредственно выводящее на экран ошибку, предупреждает диалоговое окно

NSAlert *theAlert = [NSAlert alertWithError:theError];
NSInteger button = [theAlert runModal];
if (button != NSAlertFirstButtonReturn) {
    // handle
}

Создание и возврат объектов NSError

Можно объявить и реализовать собственные методы, косвенно возвращающиеся NSError объект. Методы, которые являются хорошими кандидатами на NSError параметры - те, которые открывают файлы и файлы чтения, ресурсы загрузки, анализируют форматированный текст и т.д. В целом эти методы не должны указывать ошибку посредством существования NSError объект. Вместо этого они должны возвратиться NO или nil от метода, чтобы указать, что произошла ошибка. Возвратитесь NSError объект описать ошибку.

Если Вы собираетесь возвратиться NSError объект ссылкой в реализации такого метода, необходимо создать NSError объект. Вы создаете ошибочный объект любой путем выделения его и затем инициализации его с initWithDomain:code:userInfo: метод NSError или при помощи метода фабрики классов errorWithDomain:code:userInfo:. Как ключевые слова обоих методов указывают, необходимо предоставить инициализатор домен (строковая константа), код ошибки (целое число со знаком), и “пользовательский информационный словарь”, содержащий дескриптивную и поддерживающую информацию. (См. Ошибочные Объекты, Домены и Коды для полных описаний этих элементов данных.) Необходимо гарантировать, что локализуются все строки в пользовательском информационном словаре.

Перечисление 2-7 является примером метода, в целях иллюстрации, вызывающего уровень POSIX open функционируйте для открытия файла. Если эта функция возвращает ошибку, метод создает NSError объект NSPOSIXErrorDomain это используется в качестве базовой ошибки пользовательского ошибочного домена, возвращенного к вызывающей стороне.

Перечисление 2-7  Реализовывая метод, возвращающийся NSError объект

- (NSString *)fooFromPath:(NSString *)path error:(NSError **)anError {
 
    const char *fileRep = [path fileSystemRepresentation];
    int fd = open(fileRep, O_RDWR|O_NONBLOCK, 0);
 
    if (fd == -1) {
 
        if (anError != NULL) {
            NSString *description;
            NSDictionary *uDict;
            int errCode;
 
            if (errno == ENOENT) {
                description = NSLocalizedString(@"No file or directory at requested location", @"");
                errCode = MyCustomNoFileError;
            } else if (errno == EIO) {
                // Continue for each possible POSIX error...
            }
 
            // Create the underlying error.
            NSError *underlyingError = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain
                code:errno userInfo:nil];
            // Create and return the custom domain error.
            NSDictionary *errorDictionary = @{ NSLocalizedDescriptionKey : description,
                NSUnderlyingErrorKey : underlyingError, NSFilePathErrorKey : path };
 
            *anError = [[NSError alloc] initWithDomain:MyCustomErrorDomain
                    code:errCode userInfo:errorDictionary];
        }
        return nil;
    }
    // ...

В этом примере возвращенный ошибочный объект включает в его пользовательский информационный словарь путь, вызвавший ошибку.

Поскольку пример в Перечислении 2-7 показывает, можно использовать ошибки, происходящие из базовых подсистем, поскольку основание для ошибки возражает, что Вы возвращаетесь к вызывающим сторонам. Можно использовать повышенные исключения, которые код обрабатывает таким же образом. NSException объект совместим с NSError объект в этом его атрибуты является именем, причиной и пользовательским информационным словарем. Можно легко передать информацию в объекте исключения к ошибочному объекту.

Примечание по ошибкам и исключениям

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

Исключения (представленный NSException объекты), для программных ошибок, таких как индекс массива, выходящий за пределы или параметр недопустимого метода. Пользовательские погрешности нивелировки (представленный NSError объекты), для ошибок периода выполнения, такой как тогда, когда файл не может быть найден, или строка в определенном кодировании не может быть считана. Условия, дающие начало исключениям, вследствие программных ошибок; необходимо иметь дело с этими ошибками перед поставкой продукта. Ошибки периода выполнения могут всегда происходить, и необходимо передать их (через NSError объекты) пользователю в таком количестве подробности, как требуется.

Несмотря на то, что исключения должны идеально заботиться о том, прежде чем развертывание, поставленное приложение сможет все еще испытать исключения в результате некоторой действительно исключительной ситуации такой как “из памяти” или “загрузочного тома, не доступного”. Лучше позволять высшему уровню приложения — самого глобального объекта приложения — справляться с этими ситуациями.