Quando utilizzare -retainCount?


110

Vorrei sapere in quale situazione hai utilizzato -retainCountfinora e alla fine i problemi che possono verificarsi usandolo.

Grazie.


5
non dovresti mai usare il file -retainCount.
holex

3
(Tranne quando dovresti. È molto occasionalmente utile per aiutare a capire cosa sta succedendo, a patto che tu capisca che a volte può essere seriamente fuorviante. E, naturalmente, non è affatto consentito se usi ARC.)
Hot Licks

Risposte:


243

Non dovresti mai usare -retainCount, perché non ti dice mai nulla di utile. L'implementazione dei framework Foundation e AppKit / UIKit è opaca; non sai cosa viene trattenuto, perché viene mantenuto, chi lo mantiene, quando è stato mantenuto e così via.

Per esempio:

  • Penseresti che [NSNumber numberWithInt:1]avrebbe un valore retainCountdi 1. Non è così. È 2.
  • Penseresti che @"Foo"avrebbe un valore retainCountdi 1. Non è così. È 1152921504606846975.
  • Penseresti che [NSString stringWithString:@"Foo"]avrebbe un valore retainCountdi 1. Non è così. Ancora una volta, è 1152921504606846975.

Fondamentalmente, poiché qualsiasi cosa può trattenere un oggetto (e quindi alterarne retainCount), e poiché non hai l'origine per la maggior parte del codice che esegue un'applicazione, un oggetto non ha retainCountsignificato.

Se stai cercando di rintracciare il motivo per cui un oggetto non viene deallocato, utilizza lo strumento Perdite in Strumenti. Se stai cercando di scoprire perché un oggetto è stato deallocato troppo presto, usa lo strumento Zombi in Strumenti.

Ma non usare -retainCount. È un metodo davvero inutile.

modificare

Per favore, andate tutti su http://bugreport.apple.com e richiedete che -retainCountsia deprecato. Più persone lo chiedono, meglio è.

modifica n. 2

Come aggiornamento, [NSNumber numberWithInt:1]ora ha un retainCount9223372036854775807. Se il tuo codice si aspettava che fosse 2, il tuo codice ora è danneggiato.


4
Grazie @ Dave-Delong per i tuoi esempi.
Moszi

1
keepCount è attualmente utile per i singleton (ora la domanda è quanto siano utili i singleton ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Joe

8
@ Joe puoi creare un singleton senza sovrascrivere retainCount.
Dave DeLong

5
@ Joe ne sono consapevole; Google "object-c singleton" per tutte le discussioni sul perché quell'esempio non è molto buono.
Dave DeLong

2
Una cosa che uso - @ DaveDeLong, potresti trovare anche questo sbagliato, ma non credo - è sovrascrivere i dealloc e gli init e inserire NSLog in essi (anche con ARC). Questo mi dà un'ottima idea se gli oggetti vengano deallocati o meno, che è la vera domanda a cui di solito cerchiamo di rispondere ..
Dan Rosenstark

50

MAI!

Sul serio. Basta non farlo.

Basta seguire la linee guida di gestione della memoria e rilascia solo ciò che si alloc, newo copy(o qualsiasi cosa hai chiamato retainsu di origine).

@bbum lo ha detto meglio qui su SO , e in modo ancora più dettagliato sul suo blog .


8
Perché penserai di contare la memoria, ma lo sbaglierai.
Abizern

@ Abizern - e che dire della situazione singleton in una delle altre risposte?
Moszi

3
Per aggiungere a questo, qualsiasi informazione che potresti ottenere -retainCountpuò essere ottenuta (con molti più dettagli) da Instruments e dai suoi strumenti.
Dave DeLong

3
Per aggiungere a ciò che ha detto Dave; il numero di conservazione assoluto di un oggetto è un dettaglio di implementazione. Sia un dettaglio delle parti interne dell'oggetto e / o un dettaglio di qualsiasi altro oggetto attraverso il quale l'oggetto può essere passato. Chiamando retain, retain, retain, autorelease, autorelease, autoreleasepotrebbe essere il risultato perfettamente valido di passare un oggetto attraverso l'API UIKit, per esempio.
bbum

2
@ d11wtq Se keepCount ever == 0, la singolarità è stata raggiunta!
bbum

14

Gli oggetti rilasciati automaticamente sono un caso in cui il controllo di -retainCount non è informativo e potenzialmente fuorviante. Il conteggio di conservazione non ti dice nulla su quante volte -autorelease è stato chiamato su un oggetto e quindi quante volte verrà rilasciato quando l'attuale pool di rilascio automatico si esaurisce.


1
Grazie, questo è un buon punto. Questa è la prima risposta che in realtà ha un motivo descritto perché non utilizzare il keepCount, oltre al generico "non".
Moszi

1
@Moszi: la tua domanda era "Quando usare RetainCount?" - se non volevi fare quella domanda, avresti dovuto chiedere qualcos'altro.
Chuck

@chuck - in realtà ero interessato a "quando usarlo", tuttavia sembra che ogni risposta sarà "mai" ... Ma - immagino che tu abbia ragione. Lascerò la domanda aperta per un paio di giorni, e se non ci sarà nessuna risposta diversa da mai, allora accetterò "mai" come risposta.
Moszi

10

Io non trovo retainCounts molto utile quando si verificata con 'strumenti'.

Utilizzando lo strumento "allocazioni", assicurati che "Conteggi riferimenti record" sia attivato e puoi accedere a qualsiasi oggetto e vedere la sua cronologia keepCount.

Associando allocazioni e rilasci puoi ottenere una buona immagine di ciò che sta accadendo e spesso risolvere quei casi difficili in cui qualcosa non viene rilasciato.

Questo non mi ha mai deluso, inclusa la ricerca di bug nelle prime versioni beta di iOS.


5

Dai un'occhiata alla documentazione Apple su NSObject, copre praticamente la tua domanda: NSObject keepCount

In breve, keepCount è probabilmente inutile per te a meno che tu non abbia implementato il tuo sistema di conteggio dei riferimenti (e posso quasi garantire che non lo avrai).

Nelle parole di Apple, keepCount è "in genere di nessun valore nel debug dei problemi di gestione della memoria".


Prima di tutto grazie per la tua risposta. Di solito la reazione delle persone a questa domanda è "MAI". (Vedi le risposte). In realtà "nessun valore nel debugging" non significa "MAI". Quindi la mia domanda è: perché la forte sensazione di non usarlo (ad esempio nell'implementazione singleton - di nuovo una delle risposte)?
Moszi

Immagino che dovresti fornire maggiori informazioni su ciò per cui lo stai usando. Un utilizzo accettabile sarebbe, come suggerito da Apple, l'override di keepCount per implementare il proprio sistema di conteggio dei riferimenti. Ma in pratica, non lo vedresti mai (non l'ho mai fatto, comunque). La forte reazione viene generalmente dal fatto che la stessa Apple ha sostenuto (nei loro gruppi di posta, nei documenti, nei forum di sviluppo, ecc.) Di lasciare in pace keepCount.
lxt

1
@Moszi: il debugging è l'unica situazione in cui la maggior parte delle persone potrebbe pensare che abbia un valore, quindi se è inaffidabile lì, non è mai utile. A quali altri usi stai pensando?
Chuck

4

Ovviamente non dovresti mai usare il metodo keepCount nel tuo codice, poiché il significato del suo valore dipende da quanti rilasci automatici sono stati applicati all'oggetto e questo è qualcosa che non puoi prevedere. Tuttavia è molto utile per il debug, specialmente quando si cercano perdite di memoria nel codice che chiama metodi di oggetti Appkit al di fuori del ciclo di eventi principale, e non dovrebbe essere deprecato.

Nel tuo tentativo di esprimere il tuo punto di vista hai seriamente sopravvalutato la natura imperscrutabile del valore. È vero che non è sempre un conteggio dei riferimenti. Esistono alcuni valori speciali utilizzati per i flag, ad esempio per indicare che un oggetto non deve mai essere deallocato. Un numero come 1152921504606846975 sembra molto misterioso finché non lo scrivi in ​​esadecimale e ottieni 0xfffffffffffffff. E 9223372036854775807 è 0x7fffffffffffffff in esadecimale. E non è davvero così sorprendente che qualcuno scelga di usare valori come questi come flag, dato che ci vorrebbero quasi 3000 anni per ottenere un keepCount alto quanto il numero maggiore, supponendo che tu abbia incrementato il keepCount di 100.000.000 di volte al secondo.


3

Quali problemi puoi ottenere dall'usarlo? Tutto ciò che fa è restituire il conteggio di conservazione dell'oggetto. Non l'ho mai chiamato e non riesco a pensare a nessun motivo per farlo. L'ho sovrascritto in singleton per assicurarmi che non vengano deallocati.


2
Non c'è motivo per sovrascriverlo nel caso singleton. Non esistono percorsi di codice in Foundation / CoreFoundation da utilizzare retainCountper la gestione della memoria.
bbum

Il rilascio non lo usa per decidere se chiamare dealloc?
ughoavgfhw

2
No; l'implementazione interna di ritenzione / rilascio / rilascio automatico ha radici profonde in CoreFoundation e in realtà non è affatto quello che ci si potrebbe aspettare. Vai a prendere la fonte CoreFoundation (è disponibile) e dai un'occhiata.
bbum

3

Non dovresti preoccuparti della perdita di memoria fino a quando la tua app non è attiva e in esecuzione e fa qualcosa di utile.

Una volta che lo è, avvia Strumenti e usa l'app per vedere se si verificano davvero perdite di memoria. Nella maggior parte dei casi hai creato un oggetto da solo (quindi lo possiedi) e ti sei dimenticato di rilasciarlo dopo aver finito.

Non cercare di ottimizzare il codice mentre lo scrivi, le tue ipotesi su ciò che potrebbe perdere memoria o richiedere troppo tempo sono spesso sbagliate quando effettivamente usi l'app normalmente.

Prova a scrivere il codice corretto, ad esempio se crei un oggetto usando alloc e simili, assicurati di rilasciarlo correttamente.


0

Non dovresti mai usarlo nel tuo codice, ma potrebbe sicuramente aiutare durante il debug


0

Non utilizzare mai -retainCount nel codice. Tuttavia, se lo usi, non vedrai mai che restituisce zero. Pensa al perché. :-)


0

Gli esempi usati nel post di Dave sono NSNumber e NSStrings ... quindi, se usi altre classi, come UIViews, sono sicuro che otterrai la risposta corretta (il conteggio di conservazione dipende dall'implementazione ed è prevedibile).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.