Тип аргумента для error:
равен NSError**
(т. Е. указатель на указатель на объект).Это позволяет объекту moc
выделять и инициализировать новый объект NSError
по мере необходимости.Это общий шаблон, особенно в Какао.
Документация NSError дает некоторое представление о мотивации для этого подхода:
Приложения могут выбрать создание подклассовNSError для обеспечения лучшей локализованной строки ошибок путем переопределения localizedDescription .
Передача аргумента NSError**
позволяет этому методу возвращать любой подкласс NSError
, который имеет смысл.Если вы передали NSError*
, вам пришлось бы предоставить существующий объект NSError
, и у метода не было бы способа вернуть объект , отличный от того, который вы передали.
Для ясности, метод может выглядеть примерно так:
- (NSArray*)executeFetchRequest:(Request *)request error:(NSError**)error {
...
if ((error != NULL) && (some_error_condition)) {
*error = [[[SomeNSErrorSubclass alloc] init...] autorelease];
return nil;
}
}
Обратите внимание, что это также позволяет вызывающему коду игнорировать ошибки, просто передавая NULL
для параметра error:
, какследует:
NSArray *array = [moc executeFetchRequest:request error:NULL];
Обновление: (в ответ на вопросы):
Существует две причины, по которым тип аргумента должен быть NSError**
вместо NSError*
: 1. правила области видимости переменной и 2. экземпляры NSError являются неизменяемыми.
Причина № 1: правила области видимости переменной
Предположим, чтообъявление функции должно было выглядеть так:
- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error;
И мы должны были вызвать функцию следующим образом:
NSError * error = nil;
[someArray executeFetchRequest:someRequest error:error];
if (error != nil) { /* handle error */ }
Когда вы передадите переменную таким образом, тело функции будетне сможет изменить значение этой переменной (т.е. тело функциине сможет создать новую переменную, чтобы заменить существующую).Например, следующие назначения переменных будут существовать только в локальной области функции.Вызывающий код по-прежнему будет видеть error == nil
.
- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error {
...
error = [[[NSError alloc] init...] autorelease]; // local only
error = [[[SomeNSErrorSubclass alloc] init...] autorelease]; // local only
}
Причина № 2: экземпляры NSError неизменны
Давайте сохраним то же объявление функции, но вызовемфункционируйте так:
NSError * error = [[[NSError alloc] init...] autorelease];
[someArray executeFetchRequest:someRequest error:error];
if (error != nil) { /* handle error */ }
Прежде всего, правила переменной области видимости гарантируют, что error
не может быть nil
, поэтому условие if (error != nil) { ...
всегда будет истинным, но даже если вы захотитепроверьте наличие конкретной информации об ошибке внутри блока if
, вам не повезет, потому что экземпляры NSError
являются неизменными .Это означает, что после их создания вы не можете изменять их свойства, поэтому функция не сможет изменить domain
или userInfo
того экземпляра NSError
, который вы создали в вызывающем коде.
- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error {
...
error.domain = ... // not allowed!
error.userInfo = ... // not allowed!
}