Ответ 1
Основы: Каковы официальные причины не использовать saveCount?
Управление автозаполнениями является наиболее очевидным - у вас нет способа убедиться, что многие из ссылок, представленных retainCount
, находятся в локальной или внешней (во вторичном потоке или в другом потоке локального пула).
Кроме того, у некоторых людей есть проблемы с утечками, а также на более высоком уровне подсчета ссылок и том, как пулы autorelease работают на фундаментальных уровнях. Они напишут программу без (большого) внимания к правильному подсчету ссылок или без обучения правильному подсчету. Это делает их программу очень сложной для отладки, тестирования и улучшения - это также очень трудоемкое исправление.
Причиной обескураживания его использования (на уровне клиента) является двоякое:
1) Значение может варьироваться по многим причинам. Только потоки - причина, чтобы никогда не доверять ей.
2) Вам все равно нужно выполнить правильный подсчет ссылок. retainCount
никогда не спасет вас от несбалансированного подсчета ссылок.
Есть ли вообще какая-либо ситуация, когда это может быть полезно?
Фактически вы можете использовать его значимым образом, если вы написали свои собственные распределители или схему подсчета ссылок или если ваш объект жил в одном потоке, и у вас был доступ к любым и всем пулам автозаполнения, в которых он мог существовать. Это также подразумевает вы не будете делиться им с любыми внешними API. Легкий способ имитировать это - создать программу с одним потоком, нулевыми пулами автозапуска и сделать свою ссылку, считая "нормальный" способ. Это маловероятно, что вам когда-нибудь понадобится решить эту проблему/написать эту программу для чего угодно, кроме "академических" причин.
В качестве вспомогательного средства для отладки: вы можете использовать его, чтобы убедиться, что количество удержания не является необычно высоким. Если вы примете такой подход, помните о различиях в реализации (некоторые цитируются в этом сообщении) и не полагайтесь на него. Не отправляйте тесты в репозиторий SCM.
Это может быть полезной диагностикой в крайне редких случаях. Его можно использовать для обнаружения:
-
Сдерживание: распределение с положительным дисбалансом в счете удержания не будет отображаться как утечка, если распределение доступно вашей программе.
-
Объект, на который ссылаются многие другие объекты. Одной из иллюстраций этой проблемы является (изменяемый) общий ресурс или коллекция, который работает в многопоточном контексте. Частый доступ или изменения этого ресурса/коллекции могут привести к значительным узкое место в выполнении вашей программы.
-
Уровни авторекламы: автореализация, пулы авторекламы и циклы сохранения/авторекламы - все это связано со стоимостью. Если вам нужно минимизировать или уменьшить использование памяти и/или рост, вы можете использовать этот подход для выявления чрезмерных случаев.
Из комментария к Bavarious (ниже): высокое значение может также указывать недействительное распределение (dealloc'd instance). Это полностью детализация реализации и, опять же, не используется в производственном коде. Сообщение об этом распределении приведет к ошибке при включении зомби.
Что следует делать вместо этого?
Если вы не отвечаете за возврат памяти в self
(то есть вы не пишете распределитель), оставьте ее в покое - это бесполезно.
Вам нужно узнать правильный подсчет ссылок.
Для лучшего понимания использования релиза и авторекламы, установите некоторые точки останова и поймите, как они используются, в каких случаях и т.д. Вам все равно придется учиться правильно использовать подсчет ссылок, но это может помочь вам понять почему это бесполезно.
Еще проще: используйте Инструменты для отслеживания расчётов и подсчета ссылок, а затем проанализируйте счетчик ссылок и вызовы нескольких объектов в активной программе.
Исторический/пояснительный: Почему Apple предоставляет этот метод в протоколе NSObject, если он не предназначен для использования? Является ли код Apple для какой-либо цели полагаться на keepCount? Если да, то почему он не скрыт где-то?
Мы можем предположить, что он общедоступен по двум основным причинам:
1) Правильность подсчета ссылок в управляемых средах. Хорошо, что распределители используют retainCount
- действительно. Это очень простая концепция. Когда вызывается -[NSObject release]
, может быть вызван счетчик ref (если не переопределено), и объект может быть освобожден, если retainCount
равен 0 (после вызова dealloc). Все это хорошо на уровне распределителя. Распределители и зоны (в основном) абстрагированы так... это делает результат бессмысленным для обычных клиентов. См. Комментарий к bbum (ниже) для получения подробной информации о том, почему retainCount
не может быть равно 0 на уровне клиента, освобождению объекта, последовательностям освобождения и т.д.
2) Чтобы сделать его доступным для подклассов, которым требуется пользовательское поведение, а также потому, что другие методы подсчета ссылок являются общедоступными. Это может быть удобно в нескольких случаях, но обычно используется по неправильным причинам (например, бессмертные синглтоны). Если вам нужна ваша собственная схема подсчета ссылок, то эта семья может стоить переопределения.
Для более глубокого понимания: каковы причины, по которым у объекта может быть другой показатель сохранения, чем предполагается из кода пользователя? Можете ли вы привести какие-либо примеры *** стандартных процедур, которые могут использовать рамочный код, которые вызывают такую разницу? Существуют ли какие-либо известные случаи, когда количество удержаний всегда отличается от ожидаемого нового пользователя?
Опять же, специальные схемы подсчета ссылок и бессмертные объекты. NSCFString
литералы относятся к последней категории:
NSLog(@"%qu", [@"MyString" retainCount]);
// Logs: 1152921504606846975
Что-нибудь еще, о чем вы думаете, стоит упомянуть о файле saveCount?
Это бесполезно, как отладочная помощь. Научитесь анализировать анализ утечек и зомби и часто их использовать - даже после того, как у вас есть дескриптор подсчета ссылок.
Обновление: bbum недавно опубликовал статью под названием saveCount бесполезен. В статье содержится подробное обсуждение того, почему -retainCount
не используется в подавляющем большинстве случаев.