Восстановление с ошибок
Как описано в Восстановлении 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]; |
} |
} |