Wann soll -retainCount verwendet werden?

110

Ich würde gerne wissen, in welcher Situation Sie -retainCountbisher gearbeitet haben und welche Probleme bei der Verwendung auftreten können.

Vielen Dank.

Moszi
quelle
5
Sie sollten das niemals benutzen -retainCount.
Holex
3
(Außer wenn Sie sollten. Es ist sehr gelegentlich hilfreich zu verstehen, was los ist, solange Sie wissen, dass es manchmal ernsthaft irreführend sein kann. Und natürlich ist es überhaupt nicht erlaubt, wenn Sie ARC verwenden.)
Hot Licks

Antworten:

243

Sie sollten niemals verwenden -retainCount, da es Ihnen niemals etwas Nützliches sagt. Die Implementierung der Foundation- und AppKit / UIKit-Frameworks ist undurchsichtig. Sie wissen nicht, was aufbewahrt wird, warum es aufbewahrt wird, wer es aufbewahrt, wann es aufbewahrt wurde und so weiter.

Beispielsweise:

  • Sie würden denken, [NSNumber numberWithInt:1]das hätte eine retainCountvon 1. Das tut es nicht. Es ist 2.
  • Sie würden denken, @"Foo"das hätte eine retainCountvon 1. Das tut es nicht. Es ist 1152921504606846975.
  • Sie würden denken, [NSString stringWithString:@"Foo"]das hätte eine retainCountvon 1. Das tut es nicht. Wieder ist es 1152921504606846975.

Grundsätzlich ist die Bedeutung retainCounteines Objekts retainCountbedeutungslos , da alles ein Objekt behalten (und daher ändern ) kann und Sie nicht über die Quelle für den größten Teil des Codes verfügen, mit dem eine Anwendung ausgeführt wird.

Wenn Sie herausfinden möchten, warum ein Objekt nicht freigegeben wird, verwenden Sie das Werkzeug "Lecks" in "Instrumente". Wenn Sie herausfinden möchten, warum ein Objekt zu früh freigegeben wurde, verwenden Sie das Zombies-Tool in Instruments.

Aber nicht benutzen -retainCount . Es ist eine wirklich wertlose Methode.

bearbeiten

Bitte gehen Sie zu http://bugreport.apple.com und fordern Sie dies an-retainCount dies veraltet ist. Je mehr Leute danach fragen, desto besser.

bearbeiten # 2

Als Update hat [NSNumber numberWithInt:1]jetzt eine retainCountvon 9223372036854775807. Wenn Ihr Code 2 erwartet hat, ist Ihr Code jetzt defekt.

Dave DeLong
quelle
4
Danke @ Dave-Delong für deine Beispiele.
Moszi
1
RetainCount ist derzeit für Singletons nützlich. (Nun stellt sich die Frage, wie nützlich Singletons sind ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Joe
8
@ Joe, du kannst einen Singleton machen, ohne ihn zu überschreiben retainCount.
Dave DeLong
5
@ Joe Ich bin mir dessen bewusst; Google "Objective-C Singleton" für alle Diskussionen darüber, warum dieses Beispiel nicht sehr gut ist.
Dave DeLong
2
Eine Sache, die ich benutze - @ DaveDeLong, vielleicht finden Sie das auch falsch, aber ich glaube nicht - ist, die Deallocs und die Inits zu überschreiben und NSLogs in sie zu setzen (sogar mit ARC). Dies gibt mir eine großartige Vorstellung davon, ob Objekte freigegeben werden oder nicht, was die eigentliche Frage ist, die wir normalerweise zu beantworten versuchen.
Dan Rosenstark
50

NOCH NIE!

Ernsthaft. Tu es einfach nicht.

Folgen Sie einfach dem Management - Richtlinien - Speicher und nur freigeben , was Sie alloc, newoder copy(oder alles , was Sie genannt retainauf ursprünglich).

@bbum sagte es am besten hier auf SO und noch detaillierter auf seinem Blog .

Abizern
quelle
8
Weil du denkst, du zählst das Gedächtnis, aber du wirst es falsch machen.
Abizern
@Abizern - und was ist mit der Singleton-Situation in einer der anderen Antworten?
Moszi
3
Darüber hinaus können alle Informationen, aus denen Sie gewinnen -retainCountkönnen, (mit viel mehr Details) von Instruments und seinen Tools abgerufen werden.
Dave DeLong
3
Um zu dem hinzuzufügen, was Dave gesagt hat; Die absolute Aufbewahrungszahl eines Objekts ist ein Implementierungsdetail. Sowohl ein Detail der Interna des Objekts als auch ein Detail eines anderen Objekts, durch das das Objekt möglicherweise geführt wurde. Der Aufruf retain, retain, retain, autorelease, Autorelease, autoreleasekönnte ein perfekt gültiges Ergebnis der Übergabe eines Objekts durch das UIKit API sein, zum Beispiel.
bbum
2
@ d11wtq Wenn keepCount jemals == 0 ist, wurde die Singularität erreicht!
bbum
14

Autorelease-Objekte sind ein Fall, in dem die Überprüfung von -retainCount nicht aussagekräftig und möglicherweise irreführend ist. Die Aufbewahrungsanzahl sagt nichts darüber aus, wie oft -autorelease für ein Objekt aufgerufen wurde und wie oft es freigegeben wird, wenn der aktuelle Autorelease-Pool leer wird.

Jona
quelle
1
Danke - das ist ein guter Punkt. Dies ist die erste Antwort, die tatsächlich einen Grund hat, warum neben dem generischen "nicht" auch "keepCount" verwendet wird.
Moszi
1
@ Moszi: Ihre Frage war "Wann sollte RetainCount verwendet werden?" - Wenn Sie diese Frage nicht stellen wollten, hätten Sie etwas anderes fragen sollen.
Chuck
@chuck - eigentlich war ich daran interessiert, wann ich es verwenden soll, aber es scheint, dass jede Antwort "nie" sein wird ... Aber - ich denke, Sie haben Recht. Ich werde die Frage für ein paar Tage offen lassen, und wenn es keine andere Antwort als nie geben wird, dann werde ich "nie" als Antwort akzeptieren.
Moszi
10

Das tue ich finde RetainCounts sehr nützlich, wenn mit 'Instruments' überprüfe.

Stellen Sie mit dem Tool "Zuordnungen" sicher, dass "Referenzzähler aufzeichnen" aktiviert ist und Sie in jedes Objekt gehen und dessen RetainCount-Verlauf anzeigen können.

Durch das Koppeln von Zuordnungen und Freigaben erhalten Sie ein gutes Bild davon, was gerade passiert, und können häufig die schwierigen Fälle lösen, in denen etwas nicht freigegeben wird.

Dies hat mich nie im Stich gelassen - einschließlich der Suche nach Fehlern in frühen Beta-Versionen von iOS.

Egil
quelle
5

Schauen Sie sich die Apple-Dokumentation zu NSObject an, sie deckt Ihre Frage ziemlich genau ab: NSObject RetainCount

Kurz gesagt, RetainCount ist für Sie wahrscheinlich nutzlos, es sei denn, Sie haben Ihr eigenes Referenzzählsystem implementiert (und ich kann fast garantieren, dass Sie dies nicht haben).

Nach Apples eigenen Worten ist RetainCount "normalerweise wertlos beim Debuggen von Speicherverwaltungsproblemen".

lxt
quelle
Zunächst einmal vielen Dank für Ihre Antwort. Normalerweise ist die Reaktion der Menschen auf diese Frage "NIE". (Siehe die Antworten). Eigentlich bedeutet "kein Wert beim Debuggen" nicht "NIE". Meine Frage lautet also: Warum ist das starke Gefühl, es nicht zu verwenden (zum Beispiel bei der Singleton-Implementierung - wieder eine der Antworten)?
Moszi
Ich denke, Sie müssten mehr Informationen darüber bereitstellen, wofür Sie es verwenden. Eine akzeptable Verwendung wäre, wie von Apple vorgeschlagen, das Überschreiben von RetainCount, um Ihr eigenes Referenzzählsystem zu implementieren. Aber in der Praxis würde man das nie sehen (ich habe es sowieso nie). Die starke Reaktion kommt im Allgemeinen von der Tatsache, dass Apple selbst (in seinen Mail-Gruppen, den Dokumenten, den Entwicklerforen usw.) befürwortet hat, RetainCount in Ruhe zu lassen.
lxt
1
@Moszi: Debugging ist die einzige Situation, in der sich die meisten Menschen vorstellen können, dass es einen Wert hat. Wenn es dort also unzuverlässig ist, ist es niemals nützlich. An welche anderen Verwendungszwecke denken Sie?
Chuck
4

Natürlich sollten Sie niemals die RetainCount-Methode in Ihrem Code verwenden, da die Bedeutung ihres Werts davon abhängt, wie viele Autoreleases auf das Objekt angewendet wurden und was Sie nicht vorhersagen können. Es ist jedoch sehr nützlich für das Debuggen - insbesondere, wenn Sie Speicherlecks in Code suchen, der Methoden von Appkit-Objekten außerhalb der Hauptereignisschleife aufruft - und sollte nicht veraltet sein.

In Ihrem Bestreben, Ihren Standpunkt zu verdeutlichen, haben Sie die Undurchschaubarkeit des Wertes ernsthaft überbewertet. Es ist wahr, dass es nicht immer ein Referenzzähler ist. Es gibt einige spezielle Werte, die für Flags verwendet werden, um beispielsweise anzugeben, dass ein Objekt niemals freigegeben werden sollte. Eine Zahl wie 1152921504606846975 sieht sehr mysteriös aus, bis Sie sie hexadezimal schreiben und 0xfffffffffffffff erhalten. Und 9223372036854775807 ist 0x7fffffffffffffff in hex. Und es ist wirklich nicht so überraschend, dass sich jemand dafür entscheidet, Werte wie diese als Flags zu verwenden, da es fast 3000 Jahre dauern würde, bis ein RetainCount so hoch wie die größere Zahl ist, vorausgesetzt, Sie haben den RetainCount 100.000.000 Mal pro Sekunde erhöht.

Marc Culler
quelle
3

Welche Probleme können Sie mit der Verwendung bekommen? Es wird lediglich die Anzahl der beibehaltenen Objekte zurückgegeben. Ich habe es nie angerufen und kann mir keinen Grund vorstellen, warum ich es tun würde. Ich habe es in Singletons überschrieben, um sicherzustellen, dass sie nicht freigegeben werden.

ughoavgfhw
quelle
2
Es gibt keinen Grund, es im Singleton-Fall zu überschreiben. In Foundation / CoreFoundation gibt es keine Codepfade, die retainCountfür die Speicherverwaltung verwendet werden.
bbum
Wird das Release nicht verwendet, um zu entscheiden, ob Dealloc aufgerufen werden soll?
ughoavgfhw
2
Nee; Die interne Implementierung von Retain / Release / Autorelease hat tiefe Wurzeln in CoreFoundation und ist wirklich überhaupt nicht das, was Sie erwarten könnten. Holen Sie sich die CoreFoundation-Quelle (verfügbar) und schauen Sie sie sich an.
bbum
3

Sie sollten sich keine Sorgen über Speicherverluste machen, bis Ihre App betriebsbereit ist und etwas Nützliches tut.

Sobald dies der Fall ist, starten Sie Instruments und verwenden Sie die App, um festzustellen, ob tatsächlich Speicherlecks auftreten. In den meisten Fällen haben Sie ein Objekt selbst erstellt (also besitzen Sie es) und vergessen, es freizugeben, nachdem Sie fertig waren.

Versuchen Sie nicht, Ihren Code zu optimieren, während Sie ihn schreiben. Ihre Vermutungen darüber, was möglicherweise Speicherverlust verursacht oder zu lange dauert, sind oft falsch, wenn Sie die App tatsächlich normal verwenden.

Versuchen Sie, korrekten Code zu schreiben, z. B. wenn Sie ein Objekt mit alloc und dergleichen erstellen, und stellen Sie dann sicher, dass Sie es ordnungsgemäß freigeben.

ExitToShell
quelle
0

Sie sollten es niemals in Ihrem Code verwenden, aber es könnte definitiv beim Debuggen helfen

iosdevnyc
quelle
0

Verwenden Sie niemals -retainCount in Ihrem Code. Wenn Sie jedoch verwenden, werden Sie nie sehen, dass es Null zurückgibt. Überlegen Sie warum. :-)

hrchen
quelle
0

Die in Daves Beitrag verwendeten Beispiele sind NSNumber und NSStrings. Wenn Sie also andere Klassen wie UIViews verwenden, erhalten Sie sicher die richtige Antwort (Die Anzahl der Beibehaltungen hängt von der Implementierung ab und ist vorhersehbar).

Peng
quelle