¿Cuándo usar -retainCount?

110

Me gustaría saber en qué situación lo usó -retainCounthasta ahora y, eventualmente, los problemas que pueden ocurrir al usarlo.

Gracias.

Moszi
fuente
5
nunca debe usar el -retainCount.
holex
3
(Excepto cuando debería. En ocasiones es útil para ayudar a comprender lo que está sucediendo, siempre que comprenda que a veces puede ser seriamente engañoso. Y, por supuesto, no está permitido en absoluto si usa ARC).
Hot Licks

Respuestas:

243

Nunca debes usarlo -retainCount, porque nunca te dice nada útil. La implementación de los marcos Foundation y AppKit / UIKit es opaca; no sabe qué se retiene, por qué se retiene, quién lo retiene, cuándo se retiene, etc.

Por ejemplo:

  • Uno pensaría que [NSNumber numberWithInt:1]tendría un valor retainCountde 1. No es así. Es 2.
  • Uno pensaría que @"Foo"tendría un valor retainCountde 1. No es así. Es 1152921504606846975.
  • Uno pensaría que [NSString stringWithString:@"Foo"]tendría un valor retainCountde 1. No es así. Nuevamente, es 1152921504606846975.

Básicamente, dado que cualquier cosa puede retener un objeto (y por lo tanto alterarlo retainCount), y dado que no tienes la fuente para la mayor parte del código que ejecuta una aplicación, un objeto no retainCounttiene sentido.

Si está tratando de rastrear por qué un objeto no se desasigna, use la herramienta Fugas en Instrumentos. Si está intentando averiguar por qué se desasignó un objeto demasiado pronto, utilice la herramienta Zombies en Instrumentos.

Pero no lo use -retainCount. Es un método verdaderamente inútil.

editar

Por favor, todos vayan a http://bugreport.apple.com y soliciten que -retainCountquede obsoleto. Cuanta más gente lo pida, mejor.

editar # 2

Como actualización, [NSNumber numberWithInt:1]ahora tiene un retainCount9223372036854775807. Si su código esperaba que fuera 2, su código ahora se ha roto.

Dave DeLong
fuente
4
Gracias @ Dave-Delong por tus ejemplos.
Moszi
1
retenerCount es actualmente útil para singletons (ahora la pregunta es qué tan útiles son los singletons ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Joe
8
@Joe puedes hacer un singleton sin anular retainCount.
Dave DeLong
5
@Joe, soy consciente de eso; Google "objetivo-c singleton" para toda la discusión sobre por qué ese ejemplo no es muy bueno.
Dave DeLong
2
Una cosa que uso, @ DaveDeLong, puede que también lo encuentres mal, pero no lo creo, es sobrescribir los deallocs y los inits y poner NSLogs en ellos (incluso con ARC). Esto me da una gran idea de si los objetos se están desasignando o no, que es la pregunta real que generalmente estamos tratando de responder ..
Dan Rosenstark
50

¡NUNCA!

Seriamente. Simplemente no lo hagas.

Sólo tiene que seguir la directrices de gestión de memoria y sólo soltar lo que alloc, newo copy(o cualquier cosa que llamó retainal principio).

@bbum lo dijo mejor aquí en SO , e incluso con más detalle en su blog .

Abizern
fuente
8
Porque pensarás que estás contando la memoria, pero lo estarás haciendo mal.
Abizern
@Abizern: ¿y qué pasa con la situación de singleton en una de las otras respuestas?
Moszi
3
Para agregar a esto, cualquier información que pueda obtener -retainCountse puede obtener (con mucho más detalle) de Instruments y sus herramientas.
Dave DeLong
3
Para agregar a lo que dijo Dave; el recuento absoluto de retención de un objeto es un detalle de implementación. Tanto un detalle de las partes internas del objeto como un detalle de cualquier otro objeto por el que haya pasado el objeto. Llamando retain, retain, retain, autorelease, autorelease, autoreleasepodría ser un resultado perfectamente válido de pasar un objeto a través de la API UIKit, por ejemplo.
bbum
2
@ d11wtq Si retenerCount alguna vez == 0, ¡se ha logrado la singularidad!
bbum
14

Los objetos liberados automáticamente son un caso en el que la comprobación de -retainCount no es informativa y es potencialmente engañosa. El recuento de retención no le dice nada sobre cuántas veces se ha llamado a -autorelease en un objeto y, por lo tanto, cuántas veces se liberará cuando se agote el grupo de autorelease actual.

Jonás
fuente
1
Gracias, este es un buen punto. Esta es la primera respuesta que en realidad tiene una razón descrita por la que no se usa retenerCount, además del genérico "no".
Moszi
1
@Moszi: Tu pregunta fue "¿Cuándo usar retenerCount?" - Si no fue su intención hacer esa pregunta, debería haber preguntado algo más.
Chuck
@chuck - en realidad estaba interesado en "cuándo usarlo", sin embargo, parece que todas las respuestas serán "nunca" ... Pero, supongo que tienes razón. Dejaré la pregunta abierta por un par de días, y si no va a haber otra respuesta que no sea nunca, entonces aceptaré "nunca" como respuesta.
Moszi
10

Yo no encuentro retainCounts muy útiles en caso de control mediante 'instrumentos'.

Con la herramienta 'asignaciones', asegúrese de que 'Registrar recuentos de referencias' esté activado y de que pueda acceder a cualquier objeto y ver su historial de retención de cuentas.

Al emparejar asignaciones y lanzamientos, puede obtener una buena imagen de lo que está sucediendo y, a menudo, resolver esos casos difíciles en los que algo no se está lanzando.

Esto nunca me ha defraudado, incluida la búsqueda de errores en las primeras versiones beta de iOS.

Egil
fuente
5

Eche un vistazo a la documentación de Apple sobre NSObject, prácticamente cubre su pregunta: NSObject keepCount

En resumen, retenerCount probablemente sea inútil para usted a menos que haya implementado su propio sistema de conteo de referencias (y casi puedo garantizar que no lo tendrá).

En las propias palabras de Apple, retenerCount "normalmente no tiene ningún valor para depurar problemas de gestión de memoria".

lxt
fuente
En primer lugar gracias por tu respuesta. Por lo general, la reacción de la gente a esta pregunta es "NUNCA". (Ver las respuestas). En realidad, "sin valor en la depuración" no significa "NUNCA". Entonces, mi pregunta es: ¿por qué la fuerte sensación de no usarlo (por ejemplo, en la implementación de singleton, es una de las respuestas nuevamente)?
Moszi
Supongo que deberías proporcionar más información sobre para qué lo estás usando. Un uso aceptable sería, como lo sugirió Apple, anular retenerCount para implementar su propio sistema de conteo de referencias. Pero en la práctica, nunca verías eso (yo nunca lo hice, de todos modos). La fuerte reacción generalmente proviene del hecho de que los propios Apple han abogado (en sus grupos de correo, los documentos, los foros de desarrollo, etc.) para dejar a retenerCount solo.
lxt
1
@Moszi: La depuración es la única situación en la que la mayoría de la gente podría concebir que tenga valor, por lo que si no es confiable allí, nunca es útil. ¿En qué otros usos estás pensando?
Chuck
4

Por supuesto, nunca debe usar el método retenerCount en su código, ya que el significado de su valor depende de cuántas autorizaciones se hayan aplicado al objeto y eso es algo que no puede predecir. Sin embargo, es muy útil para la depuración, especialmente cuando busca fugas de memoria en el código que llama a métodos de objetos de Appkit fuera del bucle de eventos principal, y no debe quedar obsoleto.

En su esfuerzo por hacer su punto, exageró seriamente la naturaleza inescrutable del valor. Es cierto que no siempre es un recuento de referencia. Hay algunos valores especiales que se utilizan para las banderas, por ejemplo, para indicar que un objeto nunca debe desasignarse. Un número como 1152921504606846975 parece muy misterioso hasta que lo escribe en hexadecimal y obtiene 0xfffffffffffffff. Y 9223372036854775807 es 0x7fffffffffffffff en hexadecimal. Y realmente no es tan sorprendente que alguien elija usar valores como estos como indicadores, dado que se necesitarían casi 3000 años para obtener un valor de cuenta de retención tan alto como el número mayor, asumiendo que se incrementó la cuenta de retención de 100,000,000 veces por segundo.

Marc Culler
fuente
3

¿Qué problemas puede tener al usarlo? Todo lo que hace es devolver el recuento de retención del objeto. Nunca lo he llamado y no puedo pensar en ninguna razón por la que lo haría. Sin embargo, lo he anulado en singletons para asegurarme de que no se desasignen.

ughoavgfhw
fuente
2
No hay razón para anularlo en el caso de singleton. No hay rutas de código en Foundation / CoreFoundation que se utilicen retainCountpara la gestión de memoria.
bbum
¿Release no lo usa para decidir si debe llamar a dealloc?
ughoavgfhw
2
No; la implementación interna de retención / liberación / liberación automática tiene raíces profundas en CoreFoundation y realmente no es en absoluto lo que podría esperar. Ve a buscar la fuente de CoreFoundation (está disponible) y echa un vistazo.
bbum
3

No debe preocuparse por la pérdida de memoria hasta que su aplicación esté funcionando y haciendo algo útil.

Una vez que lo esté, encienda Instrumentos y use la aplicación y vea si realmente ocurren pérdidas de memoria. En la mayoría de los casos, creó un objeto usted mismo (por lo tanto, es de su propiedad) y olvidó liberarlo después de haber terminado.

No intente optimizar su código mientras lo escribe, sus suposiciones sobre lo que puede perder memoria o demorar demasiado a menudo son incorrectas cuando en realidad usa la aplicación normalmente.

Intente escribir el código correcto, por ejemplo, si crea un objeto usando alloc y demás, asegúrese de liberarlo correctamente.

ExitToShell
fuente
0

Nunca debe usarlo en su código, pero definitivamente podría ayudar al depurar

iosdevnyc
fuente
0

Nunca use -retainCount en su código. Sin embargo, si lo usa, nunca verá que devuelve cero. Piense por qué. :-)

hrchen
fuente
0

Los ejemplos usados ​​en la publicación de Dave son NSNumber y NSStrings ... entonces, si usa otras clases, como UIViews, estoy seguro de que obtendrá la respuesta correcta (el conteo de retención depende de la implementación y es predecible).

Peng
fuente