Чи потрібно встановити властивості на нульове співвідношення при використанні ARC?


125

Я намагаюся навчитися автоматичного підрахунку посилань в iOS 5. Тепер перша частина цього питання повинна бути легкою:

  1. Це правильно, що мені НЕ потрібно писати явні заяви про властивості випуску в мою угоду під час використання ARC? Іншими словами, чи правда, що наступне НЕ потребує явного угоди?

    @interface MyClass : NSObject
    @property (strong, nonatomic) NSObject* myProperty;
    @end
    
    @implementation MyClass
    @synthesize myProperty;
    @end
  2. Моє наступне і важливіше запитання виникає з рядка в документі Примітки до випуску ARC :

    Вам не потрібно (справді не можна) випускати змінні екземплярів, але, можливо, вам доведеться викликати [self setDelegate: nil] на системних класах та іншому коді, який не компілюється за допомогою ARC.

    Це ставить питання: як я можу знати, які системні класи не компілюються з ARC? Коли я повинен створювати власну транзакцію та явно встановлювати сильно зберігаючі властивості до нуля? Чи слід вважати, що всі класи NS та UI, що використовуються у властивостях, потребують явних операторських операцій?

Існує велика кількість інформації про SO та інших місцях щодо практики випуску резервного ivar ресурсу при використанні ручного відстеження посилань, але відносно мало про це при використанні ARC.

Відповіді:


197

Коротка відповідь : ні, вам не доведеться анулювати властивості в deallocARC.

Довга відповідь : Ви ніколи не зможете знімати властивості dealloc, навіть в ручному керуванні пам'яттю.

У MRR ви повинні звільнити своїх іварів . Видалення властивостей означає виклик сеттерів, який може викликати код, до якого він не повинен торкатися dealloc(наприклад, якщо ваш клас або підклас переосмислює сетер). Аналогічно це може викликати сповіщення KVO. Звільнення івари натомість дозволяє уникнути цієї небажаної поведінки.

В ARC система автоматично випускає будь-які ivars для вас, тому, якщо це все, що ви робите, вам навіть не потрібно реалізовувати dealloc. Однак якщо у вас є будь-які необ'єктні ivars, які потребують спеціального поводження (наприклад, виділені буфери, які вам потрібно free()), вам все одно доведеться мати справу з тими, хто знаходиться в dealloc.

Крім того, якщо ви визначили себе делегатом будь-яких об'єктів, вам слід скасувати це співвідношення dealloc(це трохи про виклик [obj setDelegate:nil]). Примітка про це для класів, які не компілюються з ARC, є кивком на слабкі властивості. Якщо клас явно позначає свою delegateвластивість як weakтоді, вам цього не потрібно робити, тому що природа слабких властивостей означає, що він зникне за вас. Однак якщо властивість позначена, assignто вам слід зняти це з нуля у вашому dealloc, інакше у класу залишиться звисаючий покажчик і, швидше за все, він вийде з ладу , якщо він спробує надіслати повідомлення делегата. Зауважте, що це стосується лише не збережених відносин, таких як делегати.


2
Це має сенс! Дозвольте запитати вас у цьому: загальний сценарій у мене є, що у мене є MyController : UIViewControllerклас, який створює та володіє UIView, а також встановлює делегат представлення для себе. Це єдиний утримуючий власник цього погляду. Коли контролер переходить у взаємодію, подання також має перейти у взаємодію. Чи має значення тоді, якщо вказівник делегата звисає?
emfurry

4
@emfurry: Напевно, це не так, оскільки до того часу, коли ваш контролер перегляду вмирає, сам погляд не повинен бути в ієрархії перегляду і нічого не повинен робити, але краще не робити припущень. Що робити, якщо робота асинхронно запланованої роботи буде виконана пізніше, а сам вигляд закінчується застарілими його контролером перегляду на короткий час (наприклад, через асинхронну роботу, яка тимчасово зберігає вигляд)? Краще просто зняти делегата, щоб бути в безпеці. Насправді, якщо розглянута думка є a UIWebView, в документах прямо зазначено, що вам потрібно зняти делегата.
Лілі Баллард

3
@zeiteisen: Ні. unsafe_unretainedточно рівнозначно assignвластивості і є нормальною поведінкою для делегатських відносин за MRR, і їх потрібно ліквідувати.
Лілі Баллард

4
Я не згоден із твердженням про не використання сетерів у взаємодії з MRC. Apple не рекомендує цього, але вони також роблять це у своєму коді. Ви можете створити нові проблеми, не використовуючи сетер. Про це є кілька великих дискусій. Те, що є імпортером, - це правильно написати сеттер (він повинен вести себе правильно, якщо ви передасте йому нульове значення), а іноді стежте за порядком угоди.
Султан

7
@Sulthan: Незалежно від використання сетерів у dealloc чи ні, це величезна банка глистів, але моє становище в основному зводиться до: ви хочете зателефонувати якомога менше коду у dealloc. Встановники мають тенденцію включати побічні ефекти, або шляхом переосмислення в підкласах, або через KVO, або інших механізмів. Особливо слід уникати побічних ефектів у боротьбі, як чуми. Якщо ви можете видалити виклик методу з dealloc, вам слід зробити це. Це спрощено вниз до: не викликайте сеттерів у взаємодії.
Лілі Баллард

2

Просто щоб дати протилежну відповідь ...

Коротка відповідь : ні, вам не доведеться анулювати автоматично синтезовані властивості в deallocARC. І не потрібно використовувати сетер для тих, хто в init.

Довга відповідь : Вам слід скасувати власні синтезовані властивості deallocнавіть у ARC. І ви повинні використовувати сетер для тих, хто в init.

Справа в тому, що ваші власні синтезовані властивості повинні бути безпечними та симетричними щодо анулювання.

Можливий налаштування таймера:

-(void)setTimer:(NSTimer *)timer
{
    if (timer == _timer)
        return;

    [timer retain];
    [_timer invalidate];
    [_timer release];
    _timer = timer;
    [_timer fire];
}

Можливий інструмент для перегляду прокрутки, перегляду таблиці, веб-перегляду, текстового поля, ...:

-(void)setScrollView:(UIScrollView *)scrollView
{
    if (scrollView == _scrollView)
        return;

    [scrollView retain];
    [_scrollView setDelegate:nil];
    [_scrollView release];
    _scrollView = scrollView;
    [_scrollView setDelegate:self];
}

Можливий інструмент для властивості KVO:

-(void)setButton:(UIButton *)button
{
    if (button == _button)
        return;

    [button retain];
    [_button removeObserver:self forKeyPath:@"tintColor"];
    [_button release];
    _button = button;
    [_button addObserver:self forKeyPath:@"tintColor" options:(NSKeyValueObservingOptions)0 context:NULL];
}

Тоді ви не повинні дублювати будь-який код dealloc, didReceiveMemoryWarning, viewDidUnload, ... і ваше майно може бути безпечно оприлюднено. Якщо вас турбували питання про відсутність властивостей dealloc, можливо, прийде час перевірити свої сетери.

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