почему здесь используется «error: & error» (target-c) - PullRequest
7 голосов
/ 01 декабря 2011

почему здесь используется "error: & error" (target-c)

NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];

не будет ли объект в target-c эффективно передаваться по ссылке в любом случае?

Ответы [ 2 ]

21 голосов
/ 01 декабря 2011

Тип аргумента для 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!
}
3 голосов
/ 01 декабря 2011

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

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

...