Почему NSError нуждается в двойной косвенности? (указатель на указатель)

Похоже, эта концепция меня беспокоит. Почему объект NSError нуждается в указателе, переданном методу, который модифицирует объект? Например, не просто ли передать ссылку на ошибку, сделайте то же самое?

NSError *anError; [myObjc doStuff:withAnotherObj error:error]; 

а затем в doStuff:

  - (void)doStuff:(id)withAnotherObjc error:(NSError *)error { // something went bad! [error doSomethingToTheObject]; } 

Почему это не работает, как большинство других шаблонов обмена объектами? Почему вместо этого мы используем ошибку: (NSError **)?

Шаблон NSError** используется, когда метод обычно возвращает некоторое значение, но вместо этого может потребоваться вернуть объект ошибки (типа NSError* ), если он не работает. В Objective-C метод может возвращать только один тип объекта, но это случай, когда вы хотите вернуть два. В C-подобных языках, когда вам нужно вернуть дополнительное значение, вы запрашиваете указатель на значение этого типа, поэтому для возврата NSError* вам нужен параметр NSError** . Более реалистичным примером может быть следующее:

 // The method should return something, because otherwise it could just return // NSError* directly and the error argument wouldn't be necessary - (NSArray *)doStuffWithObject:(id)obj error:(NSError **)error { NSArray *result = ...; // Do some work that might fail if (result != nil) { return result; } else { // Something went bad! // The caller might pass NULL for `error` if they don't care about // the result, so check for NULL before dereferencing it if (error != NULL) { *error = [NSError errorWithDomain:...]; } return nil; // The caller knows to check error if I return nil } } 

Если у вас был только параметр NSError* вместо NSError** то doStuff никогда не сможет передать объект ошибки обратно своему вызывающему.

Довольно просто:

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

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

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

Альтернативное утверждение того, что сказал n8gray:

Потому что вы не получаете объект для отправки сообщений; вы создаете объект и возвращаете его. Обычно вам нужен аргумент pointer-to-an- NSError * -variable, потому что вы можете использовать оператор return по одной вещи, и вы уже используете его с NO .

Старый вопрос, но все же я думаю, что его стоит положить здесь –

Существенным виновником является NSError . Если вы посмотрите на его ссылку на class, нет никаких методов настройки для любого из его атрибутов, то есть домена, кода или userInfo. Таким образом, нет способа, вы можете просто назначить и инициализировать NSError, передать его методу и затем заполнить информацию об переданном объекте NSError. (Если бы был метод setter, мы могли бы просто передать NSError * и сделать что-то вроде error.code = 1 в методе.)

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

Я все еще не получил полную картину, прочитав все ответы выше. Занятие непрофессионала, которое я делал ниже, помогло мне понять, что происходит. Просто поместите его там, если это поможет другим новичкам.

Предположим, что вы следуете

 @interface Class X -(void) methodX:(NSMutableArray *)array; @end 

В некоторой другой части кода вы имеете следующую последовательность

 ClassX *objectX = [[ClassX alloc] init]; NSMutableArray *arrayXX = [@[@(1), @(2)] mutableCopy]; //What is stored in arrayXX is the address in the heap at which the NSMutableArray object starts, lets call this address ZZZ //array starting at address ZZZ in the heap now contains NSNUmbers @1,@2 [objectX methodX:array] 

Когда вы вызываете [objectX methodX:array] , то, что получает метод, является копией array . Поскольку массив содержит адрес (т. Е. Является указателем), копия является особенной в том, что то, что получено, является другой переменной с адресом ZZZ в ней.

Итак, если methodX делает [array removeObjectAtIndex:0] , то объект, начинающийся с адреса ZZZ, получает влияние (теперь он содержит только один NSNUmber @ (2)). Таким образом, когда метод возвращается, исходный массив также подвергается воздействию.

Предположим, что вместо этого методX делает array = [@[@(2)] mutableCopy]; то исходный массив не будет затронут. Это потому, что вы не вошли в адрес ZZZ и что-то изменили. Вместо этого вы переписали ZZZ в копии, полученной методом, на другой адрес YYY. Адрес YYY – это начало объекта NSMUtableArray с одним элементом NSNUmber @ (2). Исходный адрес ZZZ по-прежнему содержит NSMUtableArray с двумя элементами. @ (1) и @ (2). Таким образом, когда метод возвращается, исходный массив не изменяется.

  • C не так сложно: void (* (* f ) ()) ()
  • Скрытие нулевых значений, понимание того, почему голанг не удается здесь
  • Что такое конструктор по умолчанию для указателя на C ++?
  • Как псевдоним имени функции в Fortran
  • Что такое «->» в Objective C?
  • Ошибка с адресом функции-члена в скобки
  • Как использовать массивы на C ++?
  • В чем разница между const int *, const int * const и int const *?
  • как знак амперсанда (&) работает в c ++?
  • Надежное определение количества элементов в массиве
  • Арифметика указателей
  • Давайте будем гением компьютера.