Когда использовать -retainCount?

110

Я хотел бы знать, в какой ситуации вы использовали -retainCountдо сих пор, и в конечном итоге проблемы, которые могут возникнуть при его использовании.

Спасибо.

Moszi
источник
5
вы никогда не должны использовать -retainCount.
holex 04
3
(За исключением случаев, когда это необходимо. Иногда это полезно, чтобы помочь понять, что происходит, при условии, что вы понимаете, что иногда это может серьезно вводить в заблуждение. И, конечно же, это вообще не разрешено при использовании ARC.)
Hot Licks

Ответы:

243

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

Например:

  • Можно подумать, что [NSNumber numberWithInt:1]это будет retainCount1. Это не так. Это 2.
  • Можно подумать, что @"Foo"это будет retainCount1. Это не так. Это 1152921504606846975.
  • Можно подумать, что [NSString stringWithString:@"Foo"]это будет retainCount1. Это не так. Опять же, это 1152921504606846975.

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

Если вы пытаетесь отследить, почему объект не освобождается, используйте инструмент Leaks в Instruments. Если вы пытаетесь выяснить, почему объект был освобожден слишком рано, используйте инструмент «Зомби» в инструментах.

Но не используйте -retainCount. Это действительно бесполезный метод.

редактировать

Пожалуйста, перейдите на http://bugreport.apple.com и попросите -retainCountпрекратить использование этого сервиса. Чем больше людей попросят об этом, тем лучше.

редактировать # 2

В качестве обновления [NSNumber numberWithInt:1]теперь имеет номер retainCount9223372036854775807. Если ваш код ожидал, что он будет равен 2, ваш код теперь не работает.

Дэйв Делонг
источник
4
Спасибо @ Dave-Delong за ваши примеры.
Moszi
1
keepCount в настоящее время полезен для синглтонов (теперь вопрос в том, насколько полезны синглтоны ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Joe
8
@Joe, вы можете сделать синглтон без переопределения retainCount.
Дэйв Делонг,
5
@ Джо, я знаю об этом; Погуглите "objective-c singleton" для всех обсуждений того, почему этот пример не очень хороший.
Дэйв Делонг,
2
Одна вещь, которую я использую - @ DaveDeLong, вы тоже можете найти это неправильно, но я так не думаю, - это перезаписать деаллоки и инициалы и поместить в них NSLogs (даже с ARC). Это дает мне отличное представление о том, освобождаются ли объекты от объекта или нет, и это настоящий вопрос, на который мы обычно пытаемся ответить ..
Дэн Розенстарк,
50

НИКОГДА!

Шутки в сторону. Просто не делай этого.

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

@bbum лучше всего сказал об этом здесь, на SO , а еще более подробно в своем блоге .

Abizern
источник
8
Потому что вы будете думать, что считаете память, но сделаете это неправильно.
Abizern 08
@Abizern - а как насчет одиночной ситуации в одном из других ответов?
Moszi 08
3
Чтобы добавить к этому, любую информацию, из которой вы могли бы получить, -retainCountможно получить (с гораздо более подробной информацией) из Instruments и их инструментов.
Дэйв Делонг
3
Чтобы добавить к тому, что сказал Дэйв; Абсолютный счетчик удержания объекта является деталью реализации. Как деталь внутреннего устройства объекта, так и / или деталь любого другого объекта, через который объект мог пройти. Вызов retain, retain, retain, autorelease, autorelease, autoreleaseможет быть совершенно действительным результатом прохождения объекта через UIKit API, например.
bbum 09
2
@ d11wtq Если keepCount ever == 0, сингулярность достигнута!
bbum 09
14

Автоматически выпущенные объекты - это один из случаев, когда проверка -retainCount неинформативна и может вводить в заблуждение. Счетчик сохранения ничего не говорит вам о том, сколько раз -autorelease было вызвано для объекта и, следовательно, сколько раз он будет освобожден, когда текущий пул автозапуска истощится.

Иона
источник
1
Спасибо - это хороший момент. Это первый ответ, в котором на самом деле описана причина, по которой не следует использовать keepCount, помимо общего «не делать».
Moszi
1
@Moszi: Ваш вопрос был "Когда использовать keepCount?" - если вы не хотели задавать этот вопрос, вам следовало спросить что-то другое.
Чак
@chuck - на самом деле меня интересовало, «когда это использовать», однако кажется, что каждый ответ будет «никогда» ... Но - я думаю, вы правы. Я оставлю вопрос открытым на пару дней, и если не будет другого ответа, кроме «никогда», то я приму «никогда» в качестве ответа.
Moszi 08
10

Я действительно найти retainCounts очень полезные при проверке с помощью «Инструменты».

Используя инструмент «распределения», убедитесь, что «Записывать счетчики ссылок» включен, и вы можете войти в любой объект и просмотреть его историю сохранения.

Объединяя аллоки и выпуски, вы можете получить хорошее представление о том, что происходит, и часто решать те сложные случаи, когда что-то не выпускается.

Это меня никогда не подводило, включая поиск ошибок в ранних бета-версиях iOS.

Эгиль
источник
5

Взгляните на документацию Apple по NSObject, она в значительной степени покрывает ваш вопрос: NSObject keepCount

Короче говоря, keepCount, вероятно, бесполезен для вас, если вы не реализовали свою собственную систему подсчета ссылок (и я почти гарантирую, что у вас ее не будет).

По словам Apple, keepCount «обычно не имеет значения при отладке проблем с управлением памятью».

LXT
источник
Прежде всего, спасибо за ответ. Обычно люди реагируют на этот вопрос «НИКОГДА». (Смотрите ответы). На самом деле «отсутствие значения при отладке» не означает «НИКОГДА». Итак, мой вопрос - почему возникает сильное ощущение того, что он не используется (например, в одноэлементной реализации - снова один из ответов)?
Moszi 08
Я думаю, вам нужно будет предоставить больше информации о том, для чего вы его используете. Приемлемым использованием будет, как предлагает Apple, переопределение keepCount для реализации вашей собственной системы подсчета ссылок. Но на практике вы никогда этого не увидите (по крайней мере, я никогда не видел). Резкая реакция обычно возникает из-за того, что сами Apple рекомендовали (в своих почтовых группах, документации, на форумах разработчиков и т. Д.) Не трогать keepCount.
lxt 08
1
@Moszi: Отладка - единственная ситуация, в которой большинство людей могло представить себе, что она имеет ценность, поэтому, если она там ненадежна, она никогда не будет полезной. Какие еще варианты использования вы думаете?
Чак
4

Конечно, вы никогда не должны использовать метод keepCount в своем коде, поскольку значение его значения зависит от того, сколько автозапусков было применено к объекту, а это то, что вы не можете предсказать. Однако это очень полезно для отладки - особенно когда вы ищете утечки памяти в коде, который вызывает методы объектов Appkit вне основного цикла событий - и его не следует исключать.

Пытаясь донести свою точку зрения, вы серьезно переоценили непостижимую природу ценности. Верно, что это не всегда счетчик ссылок. Есть некоторые специальные значения, которые используются для флагов, например, чтобы указать, что объект никогда не должен быть освобожден. Число вроде 1152921504606846975 выглядит очень загадочно, пока вы не запишете его в шестнадцатеричном формате и не получите 0xfffffffffffffff. А 9223372036854775807 - это 0x7fffffffffffffff в шестнадцатеричном формате. И это действительно не так уж удивительно, что кто-то решил использовать такие значения в качестве флагов, учитывая, что для получения keepCount, равного большему числу, потребуется почти 3000 лет, при условии, что вы увеличили keepCount 100000000 раз в секунду.

Марк Каллер
источник
3

Какие проблемы могут возникнуть при его использовании? Все, что он делает, это возвращает счетчик удержания объекта. Я никогда не звонил ему и не могу придумать ни одной причины, по которой я бы стал. Я переопределил его в синглтонах, чтобы убедиться, что они не освобождены.

ughoavgfhw
источник
2
Нет причин переопределять его в случае синглтона. В Foundation / CoreFoundation нет путей кода, которые используются retainCountдля управления памятью.
bbum 09
Разве релиз не использует его, чтобы решить, должен ли он вызывать dealloc?
ughoavgfhw 09
2
Нет; внутренняя реализация сохранения / выпуска / автоматического выпуска имеет глубокие корни в CoreFoundation и на самом деле совсем не то, что вы могли ожидать. Возьмите исходный код CoreFoundation (он доступен) и посмотрите.
bbum 09
3

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

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

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

Попытайтесь написать правильный код, например, если вы создаете объект с помощью alloc и т. Д., Убедитесь, что вы правильно его выпустили.

ExitToShell
источник
0

Вы никогда не должны использовать его в своем коде, но он определенно может помочь при отладке

iosdevnyc
источник
0

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

hrchen
источник
0

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

Peng
источник