2015-05-14 3 views
-1

Я пишу следующий код:В чем разница между * a и ** a в объекте-c?

NSArray *array = @[@1, @2]; 

Как вывести *array и **array, и в чем разница между ними?

+2

Очевидно, что «один символ' * 'означает« указатель на ... », в то время как« double '*' »означает:« указатель * на указатель * на ». Во многих ситуациях, подобных этому, «ваш лучший друг - это карандаш и лист бумаги». * Извлеките это ... сделайте диаграмму ... на бумаге. * –

+0

'NSArray * array' является указателем на экземпляр NSArray. 'NSArray ** array' является указателем на _a указатель на экземпляр NSArray. – aroth

+2

Я рекомендую вам буквально разыгрывать «массив». Вы узнаете что-то интересное о языке – CodaFi

ответ

2

Есть несколько ответов, но я думаю, что ни одна из них не поможет вам, потому что они описывают технический смысл. Давайте посмотрим на первую декларацию:

NSArray *array …; 

Когда кто-то говорит об этом коде, вы найдете такие заявления array является экземпляр объект NSArray. Даже каждый опытный разработчик Objective-C знает реальный смысл этого утверждения, это просто неправильно. Какое правильное утверждение?

А. Экземпляр объект NSArray

объекта экземпляра есть состояние, в основном набор данных, хранящихся. Для этого ему нужна память, которая сохраняется при создании объекта. Вы не имеете дело с этим, но это делается внутри +alloc. Это выполняется явно во время выполнения программы («на куче», «распределение кучи»).

… [NSArray alloc] … // Get memory for an instance object of type NSArray 

Вы адресуете такой объект исключительно по его адресу, номер первой ячейки памяти занимаемой области памяти. (Каждая ячейка памяти имеет номер, называемый адресом. Да, он похож на адреса жителей в доме по номеру дома на улице. Поэтому вы можете представить себе память как очень длинную улицу.)

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

Краткая версия: Объект instane является областью памяти и адресуется исключительно по номеру первой ячейки памяти (местоположения).

B. Указатель на объект экземпляра (ссылка)

Но если экземпляр объекта адресуется через его во время выполнения, как может мое дело код с ним? Фокус в том, что число хранится в переменной. (Смотря на стандарт C, который не совсем корректен. Говорят, что он хранится в объекте, но эти объекты не имеют ничего общего с объектами Objective-C, и я сосредоточусь на переменных, подтипе объектов.)

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

NSArray * array; 

означает: переменный указатель с идентификатором array, который хранит местоположение объекта экземпляра типа NSArray.

(Адреса являются числами, они являются целыми числами, поэтому существует связь между переменными-указателями и целыми числами, а вы можете применять вычисления к этим числам, называемым «pointer arithmetics». В некоторых ситуациях это важно для разработчиков C, но не для вас, как для разработчика Objective-C.)

Память для этой переменной не зарезервирована явно с +alloc, но неявно, когда вы вводите область своего кода, где объявлена ​​переменная. (Не совсем правильно снова, но достаточно для этого объяснения.) Итак, давайте посмотрим еще раз на очень сводились версии создания объекта:

- (void)method 
{ 
    NSArray *array = [NSArray alloc]; 
} 

Правая часть этой зарезервированной памяти заявление для экземпляра объекта и возвращает номер, адрес области памяти. Этот номер присваивается ссылке, которая называется array. Память для этой ссылки (она хранит что-то, поэтому она нуждается в памяти) зарезервирована неявно через ее определение.

Указатели на объекты обычно называются ссылками.

Краткая версия: Таким образом, array является ссылкой на объект экземпляра, сохраняющий адрес объекта экземпляра.

С. Указатель на указатель на объект экземпляра

Хорошо, мы имеем объект экземпляра, который занимает память для сохранения состояния объекта, адресуемых через его ячейку памяти (адрес). Затем мы имеем переменную, которая хранит этот адрес, ссылку array. Вы можете адресовать это через свой идентификатор.

Но иногда полезно - у меня будет пример ниже - для обращения к ссылочной переменной через свой адрес тоже. Вы можете получить адрес переменной, используя адресный оператор &.

&array 

Что вы получаете: Адрес переменной, хранящей адрес экземпляра объекта. Тип такой двойной косвенности («адрес ... адрес ...») является

NSArray ** array; 

Это, потому что в определении переменной * означает «адрес».

Краткая версия: указатель на ссылку - это переменная, в которой хранится адрес переменной, в которой хранится адрес экземпляра объекта. Он объявлен **. (Да, вы можете иметь больше уровня indirections ... Нет, это не легче понять.)

D. Примеров использования указателей ссылки

Обычно вам не нужно такое двойное indirections в Objective-C. Но есть один важный прецедент - параметр ошибки. Для того, чтобы понять, что мы будем смотреть на метод с одним параметром indirected, как вы знаете:

- (BOOL)methodThatCanProduceAnError:(NSError*)error 
{ 
    … 
    error = [NSError alloc] … // Create an error object and store its address to the reference variable error. 
    return NO; 
    … 
} 

Этот метод должен генерировать ошибку с помощью его параметра error.

Вы "называть" такой способ с кодом так:

… 
NSError *error; // A reference variable pointing to an instance object of type NSError 
error = nil; // I do not have an error, so it points to "nothing". 
[anInstance methodThatCanProduceAnError:error]; 

Что происходит? Вы передаете адрес объекта экземпляра этому методу в качестве аргумента. Вы передаете nil за сообщение «У меня нет ошибки». Это совершенно очевидно, потому что метод должен передать ссылку на объект экземпляра.

Итак, интересная часть находится внутри метода, когда он создает объект ошибки и пытается его передать. Это не работает!

В аргументах Objective-C всегда передаются значения. Это означает, что значение аргумента в «вызывающем коде» принимается и присваивается переменной внутри «вызываемого кода». Эта переменная называется переменной параметра. Когда метод пытается изменить значение переменной

error = [NSError alloc] … // Create an error object and store its address to the reference variable error. 

он исключительно изменяет значение переменной-копии внутри метода. Новая ссылка никогда не найдет выход из метода, а переменная error в вызывающем коде остается нетронутой. В «код вызова» error все еще имеет свое старое значение nil.

Таким образом, нам нужен способ изменить содержание ссылки внутри «кода вызова». Мы делаем это, передавая адрес ссылки на метод:

- (BOOL)methodThatCanProduceAnError:(NSError**)error // double indirection 
{ 
    … 
    *error = [NSError alloc] … // *error is a reference to an object 
    return NO; 
    … 
} 

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

Поэтому мы можем передать адрес ссылки:

NSError *error; // A reference variable pointing to an instance object of type NSError 
error = nil; // I do not have an error, so it points to "nothing". 
NSError ** pointerToError = &error; // The address of the reference. 
[anInstance methodThatCanProduceAnError:pointerToError]; 

Теперь метод изменяет содержимое исходной переменной. Ошибка передается.

+0

Конечно, спасибо. С & Р. –

+0

Что не так сказать о том, что 'array' является экземпляром NSArray? Говорит все, что вам нужно знать прямо сейчас, – CodaFi

+1

Нет, не всегда. Просто имейте изменяемый массив и две ссылки: 'array1' и' array2'. «array1 - это экземпляр NSArray», а «array2 - экземпляр NSArray» охватывает тот факт, что изменение * экземпляра * через одну * ссылку * также изменило бы «другой» экземпляр. Обычно у вас нет таких проблем, поэтому достаточно сказать, что «массив является экземпляром». Но это то, что я сказал в A. –