Восстановление с ошибок
Как описано в Восстановлении Attempter, NSError объект может иметь определяемое восстановление attempter, объект, пытающийся восстановиться с ошибки, если пользователь запрашивает его. Ошибочный объект содержит ссылку на восстановление attempter в его пользовательском информационном словаре, поэтому если ошибочный объект роздан в приложении, восстановление attempter остается с ним. Пользовательский информационный словарь должен также содержать опции восстановления, массив локализованных строк для заголовков кнопки, один или больше которых запрашивает восстановление. Когда ошибка представлена на предупреждении, и пользователь выбирает опцию восстановления, сообщение отправляется в восстановление attempter, запрашивая его выполнить его работу.
Идеально, восстановление attempter должно быть независимым объектом, знающим что-то об условиях ошибки и как лучше всего обойти те условия. Приложение могло даже иметь объект, роль которого должна восстановиться с ошибок различных видов. Восстановление attempter должно реализовать по крайней мере один из двух методов NSErrorRecoveryAttempting неофициальный протокол: attemptRecoveryFromError:optionIndex:delegate:didRecoverSelector:contextInfo: или attemptRecoveryFromError:optionIndex:. Это реализует прежний метод для представленного документа модально предупреждений ошибки и последний метод для модальных приложением предупреждений.
Необходимо также подготовить ошибочный объект так, чтобы восстановление после ошибки могло иметь место. Чтобы сделать это, добавьте три элемента к пользовательскому информационному словарю ошибочного объекта:
Объект восстановления-attempter под ключом
NSRecoveryAttempterErrorKeyОпции восстановления, массив локализованных строк, под ключом
NSLocalizedRecoveryOptionsErrorKeyСтрока предложения восстановления, также локализованная, под ключом
NSLocalizedRecoverySuggestionErrorKey. Несмотря на то, что это свойство строго не требуется, ошибка предупреждают, что восстановление предложений как опция должно вывести на экран эту строку, как предусмотрено инструкциями интерфейса пользователя. И если строка обращается к определенным заголовкам кнопки, она должна использовать те же заголовки в массиве options восстановления.Для инструкций об ошибочных предупреждениях на OS X см. Инструкции по Интерфейсу пользователя OS X (раздел по диалоговым окнам в “Инструкциях по Элементу UI: Windows”).
Перечисление 5-1 иллюстрирует случай, включающий NSXMLDocument класс. В этом примере, NSDocument возразите пытается создать внутреннее дерево, представляющее XML-документ с помощью initWithContentsOfURL:options:error: метод NSXMLDocument. Если попытка перестала работать, обычная причина состоит в том, что источник, XML уродлив — например, существует недостающий конечный тэг для элемента, или значение атрибута не заключается в кавычки. Если источник, XML «приведен в порядок» сначала для решения структурных проблем, может быть возможно создать дерево XML.
В примере в Перечислении 5-1, если вызов initWithContentsOfURL:options:error: возвращает ошибочный объект ссылкой, объект документа настраивает ошибочный объект, добавляя (среди прочего) объект восстановления-attempter, локализованные опции восстановления и локализованное предложение восстановления к его пользовательскому информационному словарю. Тогда это отправляет presentError:modalForWindow:delegate:didPresentSelector:contextInfo: к self.
Перечисление 5-1 , Подготавливающееся к восстановлению после ошибки
- (BOOL)readFromURL:(NSURL *)furl ofType:(NSString *)type error:(NSError **)anError { |
NSError *err; |
// xmlDoc is an NSXMLDocument instance variable. |
if (xmlDoc != nil) { |
xmlDoc = nil; |
} |
xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:furl |
options:NSXMLNodeOptionsNone error:&err]; |
if (xmlDoc == nil && err) { |
NSString *newDesc = [[err localizedDescription] stringByAppendingString: |
([err localizedFailureReason] ? [err localizedFailureReason] : @"")]; |
NSDictionary *newDict = @{ NSLocalizedDescriptionKey : newDesc, |
NSURLErrorKey : furl, |
NSRecoveryAttempterErrorKey : self, |
NSLocalizedRecoverySuggestionErrorKey : |
NSLocalizedString(@"Would you like to tidy the XML and try again?", @""), |
NSLocalizedRecoveryOptionsErrorKey : |
@[NSLocalizedString(@"Try Again", @""), NSLocalizedString(@"Cancel", @"")] }; |
NSError *newError = [[NSError alloc] initWithDomain:[err domain] |
code:[err code] userInfo:newDict]; |
[self presentError:newError modalForWindow:[self windowForSheet] |
delegate:self |
didPresentSelector:@selector(didPresentErrorWithRecovery:contextInfo:) |
contextInfo:nil]; |
} |
// ... |
Обратите внимание на то, что объект документа также добавляет к пользовательскому информационному словарю URL, идентифицирующий источник XML. Восстановление attempter будет использовать этот URL, когда оно попытается создать дерево, представляющее XML.
От ошибочного объекта отказываются цепочка ошибочного респондента и NSApp дисплеи это. Когда пользователь нажимает любую кнопку ошибочного предупреждения, NSApp проверки, чтобы видеть, имеет ли ошибочный объект и восстановление attempter и опции восстановления. Если оба из этих условий являются истиной, она вызывает метод, реализованный восстановлением attempter, который соответствует режиму предупреждения (т.е. модальный документом или модальный приложением).
Перечисление 5-2 показывает, как восстановление attempter для XML-документа реализует attemptRecoveryFromError:optionIndex:delegate:didRecoverSelector:contextInfo: метод.
Перечисление 5-2 , Восстанавливающееся с ошибки и сообщающее модальному делегату
- (void)attemptRecoveryFromError:(NSError *)error |
optionIndex:(unsigned int)recoveryOptionIndex |
delegate:(id)delegate |
didRecoverSelector:(SEL)didRecoverSelector |
contextInfo:(void *)contextInfo { |
BOOL success = NO; |
NSError *err; |
NSInvocation *invoke = [NSInvocation invocationWithMethodSignature: |
[delegate methodSignatureForSelector:didRecoverSelector]]; |
[invoke setSelector:didRecoverSelector]; |
if (recoveryOptionIndex == 0) { // Recovery requested. |
xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:[[error userInfo] |
objectForKey:NSURLErrorKey] options:NSXMLDocumentTidyXML error:&err]; |
if (xmlDoc != nil) { |
success = YES; |
} |
} |
[invoke setArgument:(void *)&success atIndex:2]; |
if (err) |
[invoke setArgument:&err atIndex:3]; |
[invoke invokeWithTarget:delegate]; |
} |
Ключевая роль вышеупомянутого примера является тестом, который восстановление attempter делает, чтобы определить, нажал ли пользователь кнопку «Try Again»: это проверяет значение recoveryOptionIndex. Если пользователь действительно нажимал эту кнопку, восстановление attempter вызывает initWithContentsOfURL:options:error: метод снова, на сей раз с NSXMLDocumentTidyXML опция. Тогда это создает и вызывает NSInvocation объект, таким образом отправляя требуемое сообщение модальному делегату ошибочного предупреждения. Объект вызова включает эти два параметра, требуемые селектором делегата: булевская переменная, указывающая, успешно выполнилась ли попытка восстановления и “информационный параметр” контекста, в этом случае, содержащий любой ошибочный объект, возвратилась из попытки восстановления.
Когда модальный делегат получает сообщение от восстановления attempter, как в Перечислении 5-3, это может ответить соответственно.
Перечисление 5-3 Модальный делегат, отвечающий на восстановление attempter
- (void)didPresentErrorWithRecovery:(BOOL)didRecover |
contextInfo:(void *)contextInfo { |
NSError *theError = (NSError *)contextInfo; |
if (didRecover) { |
[tableView reloadData]; |
} else if (theError && [theError isKindOfClass:[NSError class]]) { |
[NSAlert alertWithError:theError]; |
} |
} |