У яких ситуаціях нам потрібно записати класифікатор права власності __autoreleasing під ARC?


118

Я намагаюся завершити пазл.

__strongє за замовчуванням для всіх вказівників об'єкта, доступних до об'єктів, таких як NSObject, NSString, тощо. ARC врівноважує його з a -releaseв кінці області.

__unsafe_unretainedдорівнює старому способу. Він використовується для слабкого вказівника без збереження об'єкта, який можна отримати.

__weakце як __unsafe_unretainedвиняток, що це слабке посилання з автоматичним зануленням, що означає, що покажчик буде встановлений на нуль, як тільки розміщений посилається об'єкт. Це виключає небезпеку звисання покажчиків та помилок EXC_BAD_ACCESS.

Але для чого саме __autoreleasingдобре? Мені важко знайти практичні приклади, коли мені потрібно використовувати цей класифікатор. Я вважаю, що це лише для функцій та методів, які очікують покажчик-покажчик, такий як:

- (BOOL)save:(NSError**);

або

NSError *error = nil;
[database save:&error];

який під ARC повинен бути заявлений таким чином:

- (BOOL)save:(NSError* __autoreleasing *);

Але це занадто розпливчасто, і я хотів би повністю зрозуміти, чому . У кодових фрагментах я знаходжу місце __авторелізингу між двома зірками, що мені здається дивним. Тип є NSError**(покажчик-покажчик на NSError), тож чому розміщувати __autoreleasingміж зірками, а не просто перед NSError**?

Також можуть бути інші ситуації, в яких я повинен покластися __autoreleasing.


1
У мене є те саме запитання, і відповіді, наведені нижче, не є абсолютно переконливими ... наприклад, чому система не надає інтерфейси, які приймають NSError ** аргументи, задекларовані за допомогою __autoreleasing decorator, як ви, і примітки до випуску Arc, які говорять про те має бути? наприклад, будь-яка з багатьох цих процедур в NSFileManager.h ??
тато

Відповіді:


67

Ти маєш рацію. Як пояснюється в офіційній документації:

__авторелізинг для позначення аргументів, які передаються посиланням (id *) і автоматично випускаються при поверненні.

Все це дуже добре пояснено в посібнику з переходу ARC .

У вашому прикладі NSError декларація означає __strongнеявно:

NSError * e = nil;

Буде перетворено на:

NSError * __strong error = nil;

Коли ви телефонуєте своєму saveметоду:

- ( BOOL )save: ( NSError * __autoreleasing * );

Потім компілятору доведеться створити тимчасову змінну, встановлену на __autoreleasing. Так:

NSError * error = nil;
[ database save: &error ];

Буде перетворено на:

NSError * __strong error = nil;
NSError * __autoreleasing tmpError = error;
[ database save: &tmpError ];
error = tmpError;

Ви можете уникнути цього, оголосивши об'єкт помилки __autoreleasingбезпосередньо.


3
Ні, __autoreleasingвикористовується лише для аргументів, переданих посиланням. Це особливий випадок, оскільки у вас є вказівник на вказівник об’єкта. Це не так з такими речами, як конструктори зручності, оскільки вони повертають лише вказівник на об'єкт, а ARC обробляє його автоматично.
Macmade

7
Чому класифікатор __авторелізингу розміщується між зірками, а не тільки перед NSError **? Мені це дивно виглядає, оскільки тип - NSError **. Або це тому, що це намагається вказати, що вказівник на NSError * має бути кваліфікований як вказівка ​​на автоматично випущений об'єкт?
Гордий член

1
@Proud Член щодо вашого першого коментаря - це неправильно (якщо я вас правильно зрозумів) - див. Відповідь Глена Лоуза нижче. Об'єкт помилки створюється і присвоюється змінній для автоматичного вивільнення (тієї, яку ви передали) всередині функції збереження. Це призначення призводить до збереження та автоматичного випуску об'єкта на той час. Оголошення функції збереження заважає нам надсилати їй що-небудь, крім автоматичної змінної змінної, тому що саме цього потрібно - саме тому компілятор створює тимчасову змінну, якщо ми спробуємо.
Колін

2
То чому, схоже, ні в одному з інтерфейсів Apple цього немає? наприклад, все в NSFileManager.h?
Тато

1
@Macmade: Я випадково помітив, що вашу відповідь було відредаговано (автор stackoverflow.com/users/12652/comptrol ), і у мене складається враження, що принаймні зміни у вашому першому прикладі ("неявно ... будуть перетворені на ...) помиляються, оскільки класифікатор __strong переміщений з другого рядка в перший рядок. Можливо, ви могли це перевірити.
Martin R

34

Слідкуючи за відповіддю Макмаде та подальшим запитанням гордого члена в коментарях, (він також розмістив би це як коментар, але він перевищує максимальну кількість символів):

Ось чому змінна класифікатор __авторелізингу розміщується між двома зірками.

Для передмови правильний синтаксис оголошення об’єкта покажчика за допомогою класифікатора:

NSError * __qualifier someError;

Компілятор пробачить це:

__qualifier NSError *someError;

але це не правильно. Дивіться посібник з переходу Apple ARC (прочитайте розділ, який починається "Ви повинні правильно прикрасити змінні ...").

Щоб вирішити відповідне питання: Подвійний вказівник не може мати кваліфікатора управління пам'яттю ARC, оскільки вказівник, який вказує на адресу пам'яті, є вказівником на примітивний тип, а не вказівник на об'єкт. Однак, коли ви оголошуєте подвійний покажчик, ARC хоче знати, які правила управління пам'яттю є для другого вказівника. Ось чому подвійні змінні вказівника задаються як:

SomeClass * __qualifier *someVariable;

Отже, у випадку аргументу методу, який є подвійним покажчиком NSError, тип даних оголошується як:

- (BOOL)save:(NSError* __autoreleasing *)errorPointer;

що англійською мовою говорить "вказівник на __autoreleasing NSError вказівник об'єкта".


15

Остаточна специфікація ARC каже , що

Для __autoreleasing об'єктів новий покажчик зберігається, автоматично вивільняється та зберігається у lvalue за допомогою примітивної семантики.

Так, наприклад, код

NSError* __autoreleasing error = someError;

насправді перетворюється на

NSError* error = [[someError retain] autorelease];

... ось чому він працює, коли у вас є параметр NSError* __autoreleasing * errorPointer, тоді викликаний метод призначить помилку, *errorPointerі вищезазначена семантика запуститься.

Ви можете використовувати __autoreleasingв іншому контексті, щоб примусити об’єкт ARC до пулу автоматичних випусків, але це не дуже страшно, оскільки ARC, як видається, використовує пул автовипуску при поверненні методу і вже обробляє це автоматично.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.