Коли використовувати -retainCount?


110

Мені хотілося б дізнатися, в якій ситуації ви використовували до -retainCountцього часу, і врешті-решт проблеми, які можуть трапитися з його використанням.

Дякую.


5
ви ніколи не повинні користуватися цим -retainCount.
holex

3
(За винятком випадків, коли це потрібно. Дуже часто корисно допомогти зрозуміти, що відбувається, доки ви розумієте, що це може часом серйозно вводити в оману. І, звичайно, це взагалі не дозволено, якщо використовувати ARC.)
Hot Licks

Відповіді:


243

Ніколи не слід користуватися -retainCount, тому що це ніколи не говорить вам нічого корисного. Реалізація рамок Foundation та AppKit / UIKit є непрозорою; ви не знаєте, що зберігається, чому він зберігається, хто його зберігає, коли він зберігається тощо.

Наприклад:

  • Ви можете подумати, що це [NSNumber numberWithInt:1]було б retainCount1. Це не так. Це 2.
  • Ви можете подумати, що це @"Foo"було б retainCount1. Це не так. Це 1152921504606846975.
  • Ви можете подумати, що це [NSString stringWithString:@"Foo"]було б retainCount1. Це не так. Знову ж таки, це 1152921504606846975.

В основному, оскільки що-небудь може зберегти об'єкт (і, отже, змінити його retainCount), і оскільки у вас немає джерела більшості коду, який запускає додаток, об'єкт retainCountбезглуздий.

Якщо ви намагаєтеся відстежити, чому об’єкт не розміщується, скористайтеся інструментом "Витоки" в "Інструменти". Якщо ви намагаєтеся відстежити, чому об’єкт був розміщений занадто рано, скористайтеся інструментом Zombies в інструментах.

Але не використовуйте -retainCount. Це справді нікчемний метод.

редагувати

Будь ласка, усі перейдіть на сторінку http://bugreport.apple.com і попросіть -retainCountзастаріти. Чим більше людей, які просять про це, тим краще.

правка №2

Як оновлення, [NSNumber numberWithInt:1]тепер є retainCount9223372036854775807. Якщо ваш код очікував, що він буде 2, ваш код тепер зламався.


4
Дякуємо @ Dave-Delong за ваші приклади.
Моссі

1
наразі retainCount корисний для одиночних клавіш. (Тепер питання в тому, наскільки корисні одинаки ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Джо

8
@Joe, ви можете зробити одиночне без перекреслення retainCount.
Дейв ДеЛонг

5
@Joe Я знаю про це; Google "target-c singleton" для всіх обговорень, чому цей приклад не дуже хороший.
Дейв ДеЛонг

2
Одне, що я використовую - @ DaveDeLong, ви також можете помилитися з цим, але я не думаю, що це - перезаписати угоди та вкладені файли та вставити в них NSLogs (навіть із ARC). Це дає мені чудове уявлення про те, чи об’єкти розмовляють чи ні. На це справжнє питання, на яке ми зазвичай намагаємось відповісти.
Dan Rosenstark

50

НІКОЛИ!

Серйозно. Просто не робіть цього.

Просто дотримуйтесь Керівництво по управлінню пам'яттю і тільки відпустити те , що ви alloc, newабо copy(або що - небудь ви назвали retainна спочатку).

@bbum сказав, що найкраще тут, на SO та ще детальніше у своєму блозі .


8
Тому що ти подумаєш, що ти рахуєш пам’ять, але будеш робити це неправильно.
Абізерн

@Abizern - а як же ситуація з одинокою в одній з інших відповідей?
Моссі

3
Щоб додати до цього, будь-яку інформацію, від якої ви могли б отримати, -retainCountможна отримати (набагато детальніше) від інструментів та її інструментів.
Дейв ДеЛонг

3
Щоб додати те, що сказав Дейв; абсолютна кількість збережених об'єктів - це деталь реалізації. Як деталь внутрішніх об'єктів, так і / або деталь будь-якого іншого об'єкта, через який об'єкт може бути переданий. Виклик retain, retain, retain, autorelease, autorelease, autoreleaseможе бути абсолютно дійсним результатом проходження об'єкта через UIKit API, наприклад.
bbum

2
@ d11wtq Якщо retainCount ever == 0, сингулярність досягнута!
bbum

14

Автомобільні об'єкти - один із випадків, коли перевірка -retainCount є неінформативною та потенційно оманливою. Кількість збережених даних нічого не говорить про те, скільки разів викликали автоматичний випуск на об’єкт, а отже, скільки часу він буде випущений, коли поточний пул автовипуску зливається.


1
Спасибі - це хороший момент. Це перша відповідь, яка насправді має описану причину, чому не використовувати retainCount, окрім загального "не".
Моссі

1
@Moszi: Ваше запитання було "Коли використовувати retainCount?" - якщо ви не хотіли задавати це питання, ви мали б запитати ще щось.
Чак

@chuck - насправді мене цікавило "коли його використовувати", проте, схоже, кожна відповідь буде "ніколи" ... Але - я думаю, ви праві. Я залишаю питання відкритим на пару днів, і якщо вже не буде відповіді, то ніколи, тоді я прийму "ніколи" як відповідь.
Моссі

10

Я дійсно знайти retainCounts дуже корисні при перевірці з допомогою «Інструменти».

За допомогою інструменту "виділення" переконайтесь, що "Записати довідкові підрахунки" увімкнено, і ви можете зайти в будь-який об'єкт і переглянути його історію retainCount.

Шляхом спарювання алоків та релізів ви можете добре уявити, що відбувається, і часто вирішувати ті складні випадки, коли щось не випускається.

Це ніколи мене не підводило - включаючи пошук помилок у ранніх бета-версіях iOS.


5

Погляньте на документацію Apple на NSObject, вона в значній мірі охоплює ваше питання: NSObject retainCount

Коротше кажучи, retainCount, ймовірно, марний для вас, якщо ви не впровадили власну систему підрахунку довідок (і я майже можу гарантувати, що у вас її не буде).

За власними словами Apple, функція retainCount "зазвичай не має значення при налагодженні проблем управління пам'яттю".


Перш за все дякую за вашу відповідь. Зазвичай реакція людей на це питання "НІКОЛИ". (Див. Відповіді). Насправді "немає значення при налагодженні" не означає "НІКОЛИ". Отже, моє запитання - чому сильне почуття не використовувати його (наприклад, в одиночній реалізації - знову одна з відповідей)?
Моссі

Я думаю, вам потрібно буде надати більше інформації про те, для чого ви його використовуєте. Прийнятне використання буде, як пропонує Apple, переосмислити функцію retainCount для впровадження власної системи підрахунку довідок. Але на практиці ти цього ніколи не побачиш (у мене все одно ніколи). Сильна реакція, як правило, випливає з того, що самі Apple виступали (у своїх поштових групах, документах, на форумах розробників тощо) залишати retainCount у спокої.
lxt

1
@Moszi: Налагодження - це єдина ситуація, в якій більшість людей може уявити, що вона має цінність, тому якщо вона там недостовірна, вона ніколи не буде корисною. Про які інші сфери використання ви думаєте?
Чак

4

Звичайно, ви ніколи не повинні використовувати метод retainCount у своєму коді, оскільки значення його значення залежить від того, скільки авторелізів було застосовано до об'єкта, і це те, що ви не можете передбачити. Однак це дуже корисно для налагодження - особливо коли ви знижуєте витоки пам’яті в коді, який викликає методи об’єктів Appkit поза основним циклом подій - і його не слід заставляти.

Намагаючись висловити свою думку, ви серйозно завищили непереборний характер цінності. Це правда, що це не завжди підрахунок. Існують деякі спеціальні значення, які використовуються для прапорів, наприклад, щоб вказати, що об'єкт ніколи не повинен бути розміщений. Таке число, як 1152921504606846975, виглядає дуже таємничим, поки ви не напишете його шістнадцятком і не отримаєте 0xfffffffffffffffff. І 9223372036854775807 - це 0x7fffffffffffffffff у шістнадцятковій кількості. І це насправді не так дивно, що хтось вирішив би використовувати такі значення, як ці, як прапори, враховуючи, що знадобиться майже 3000 років, щоб утриматиКайт вийшов більшим, ніж більша кількість, якщо припустити, що ви збільшили утримувану кількість 100 000 000 разів на секунду.


3

Які проблеми можна отримати від його використання? Все, що він робить - це повернути нерозподілений рахунок об'єкта. Я ніколи цього не називав і не можу придумати будь-якої причини, яку я хотів би. Я відмінив це в одиночних клавішах, щоб переконатися, що вони не розташовані.


2
Немає жодних підстав переосмислювати це в одиночному випадку. У Foundation / CoreFoundation немає кодових шляхів, які використовуються retainCountдля управління пам'яттю.
bbum

Не випускає використовувати його, щоб вирішити, чи слід викликати dealloc?
ughoavgfhw

2
Ніп; внутрішня реалізація функції retain / release / autorelease має глибокі корені в CoreFoundation і насправді зовсім не те, що ви могли очікувати. Займіть джерело CoreFoundation (воно доступне) і подивіться.
bbum

3

Ви не повинні турбуватися про витоку пам’яті, поки ваша програма не працює і не зробить щось корисне.

Як тільки це станеться, запустіть інструменти та скористайтеся програмою і перевірте, чи справді відбувається витік пам'яті. У більшості випадків ви створили об'єкт самостійно (таким чином ви володієте ним) і забули випустити його після того, як ви закінчили.

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

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


0

Ніколи не слід використовувати його у своєму коді, але це напевно може допомогти при налагодженні


0

Ніколи не використовуйте -retainCount у своєму коді. Однак якщо ви використовуєте, ви ніколи не побачите, що він поверне нуль. Подумайте, чому. :-)


0

Приклади, які використовуються в публікації Дейва, - NSNumber і NSStrings ... тому, якщо ви використовуєте деякі інші класи, такі як UIViews, я впевнений, що ви отримаєте правильну відповідь (кількість збереження залежить від реалізації, і це передбачувано).

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