2009-05-05 6 views
6

Hier ist eine gängige Praxis sehe ich oft (auch von einem sehr beliebten iPhone-Entwicklerbuch)iPhone Memory Management und Loslassen

In der H-Datei:

@interface SomeViewController : UIViewController 
{ 
    UIImageView *imgView; 
} 

Irgendwo in der .m-Datei:

imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] 
applicationFrame]]; 
[imgView setImage:[UIImage imageNamed:@"someimage.png"]]; 
[self addSubview:imgView]; 
[imgView release]; 

Und später, sehen wir diese ...

- (void) dealloc 
{ 
    [imgView release]; 
    [super dealloc]; 

} 

Da imgView eine passende Zuordnung und Freigabe hat, ist die Freigabe von imgView in dealloc notwendig?

Wo wird der vom addSubview-Aufruf beibehaltene imgView berücksichtigt?

Antwort

-1

Ja, das Code hat Probleme. Es veröffentlicht die imgView zu früh, die möglicherweise zu Abstürzen führen kann in seltenen Fällen speichert ein Objekt in einer Instanzvariable, ohne es zu behalten, und es geht im Allgemeinen über Speicherverwaltung der falsche Weg.

Ein richtiger Weg, dies zu tun wäre:

@interface SomeViewController : UIViewController 
{ 
    UIImageView *imgView; 
} 
@property (nonatomic, retain) UIImageView *imgView; 

Und bei der Umsetzung;

@synthesize imgView; 

Irgendwo im Modul:

//Create a new image view object and store it in a local variable (retain count 1) 
UIImageView *newImgView = [[UIImageView alloc] initWithFrame:self.view.bounds]; 
newImgView.image = [UIImage imageNamed:@"someimage.png"]; 

//Use our property to store our new image view as an instance variable, 
//if an old value of imgView exists, it will be released by generated method, 
//and our newImgView gets retained (retain count 2) 
self.imgView = newImgView; 

//Release local variable, since the new UIImageView is safely stored in the 
//imgView instance variable. (retain count 1) 
[newImgView release]; 

//Add the new imgView to main view, it's retain count will be incremented, 
//and the UIImageView will remain in memory until it is released by both the 
//main view and this controller. (retain count 2) 
[self.view addSubview:self.imgView]; 

Und die dealloc bleibt das gleiche:

- (void) dealloc 
{ 
    [imgView release]; 
    [super dealloc]; 
} 
+3

imgView wird nicht zu früh freigegeben. Es wird von addSubview beibehalten. Dies ist ein sehr Das allgemeine Idiom wird direkt nach dem Hinzufügen über addSubview (oder alle anderen Aufrufe, die beibehalten werden, z. B. PUSHViewController von UINavigationController) freigegeben. – Boon

+1

Eine etwas einfachere Methode besteht darin, den ivar (imgView) direkt zuzuweisen, anstatt später self.imgView zu verwenden. Dies beseitigt die Notwendigkeit von [newImgView release] später im Code. – Sophtware

+0

@boon Ups, du hast recht - ich denke, ich muss den Originalcode falsch gelesen haben. Auf jeden Fall ist es ein Fehler, etwas in einer Instanzvariablen zu speichern, nachdem Sie es freigegeben haben. Sie könnten schließlich Code schreiben, der eine Nachricht an das Objekt sendet, nachdem es freigegeben wurde (obwohl ich zugeben muss, dass dies in diesem speziellen Fall sehr unwahrscheinlich ist). –

9

Der Code ist falsch. Sie werden imgView freigeben, nachdem es freigegeben wurde.

In .m-Datei Sie:

  1. alloc es -> Sind Sie es
  2. es als Subview hinzufügen -> Sie und the UIView owns it
  3. release es -> Sie don ‚t besitzen sie

Dann in dealloc Sie release imgView obwohl, wie wir in Schritt 3 oben hergestellt, Sie es nicht besitzen. Wenn Sie [super dealloc] aufrufen, wird die Ansicht alle Unteransichten freigeben, und ich nehme an, Sie erhalten eine Ausnahme.

Falls Sie ein Ivar von imgView behalten wollen, schlage ich vor nichtrelease Aufruf, nachdem Sie es als ein Subview hinzufügen, und halten Sie Ihre dealloc gleich. Auf diese Weise haben Sie auch dann einen gültigen Verweis, wenn imgView aus der Ansichtshierarchie entfernt wird.

0

Der Code ist inkorrekt, Sie sollten ihn nicht in der init-Methode freigeben, nur wenn dealloc aufgerufen wird (das heißt, wenn Sie es als einen Ivar behalten möchten, brauchen Sie nicht, es sei denn, Sie benötigen einen Zeiger auf es anderswo seit addSubview: behält die Ansicht für Sie).

Ich glaube der Grund, warum es nicht wirklich abstürzt, ist, weil es immer noch von der Oberklasse (vom Aufruf zu addSubview :) beibehalten wird, also wenn es in dealloc freigegeben wird, ist das eigentlich ausgeglichen. Die Ansicht wird wahrscheinlich aus der Superansicht entfernt, wenn sie unmittelbar danach aufgehoben wird. Wenn sie [super dealloc] aufgerufen wird, wird sie nicht übersteuert. Das ist meine Vermutung, zumindest.

0

Die grundlegende Antwort ist, gibt es nur eine [imgView release] im Beispielcode sein sollte (ob es nach addSubview oder in dealloc ist). Jedoch würde ich [imgView release] von dealloc entfernen und es nach addSubview verlassen.

Es gibt einen Haken auf dem iPhone; mit didReceiveMemoryWarning, könnten Sie Objekte (einschließlich einer gesamten Ansicht) aus unter Ihnen freigegeben haben. Wenn Sie eine anwendungsweite Retain-Menge haben und den Arbeitsspeicher nicht respektieren, können Sie feststellen, dass die Anwendung einfach beendet wird.

Ein gutes Beispiel ist:
, wenn Sie von einem verschachtelten Satz von 3 Ansichten denken, Ansicht 1-> Ansicht 2-> Ansicht 3. Als nächstes betrachten die ‚viewDidLoad‘ und ‚viewDidUnload‘ nennt. Wenn sich der Benutzer momentan in "Ansicht 3" befindet, ist es möglich, dass View1 entladen wird, und dies wird dort unangenehm.
Wenn Sie ein Objekt innerhalb von viewDidLoad zugewiesen haben und es nicht freigegeben haben, nachdem Sie es zur Unteransicht hinzugefügt haben, wird Ihr Objekt nicht freigegeben, wenn view1 entladen wird, aber view1 wird noch nicht geladen.
viewDidLoad wird wieder ausgeführt und Ihr Code wird erneut ausgeführt, aber jetzt haben Sie zwei Instanzen Ihres Objekts anstelle von einem; Ein Objekt befindet sich in Nirgendwo mit der zuvor entladenen Ansicht und das neue Objekt wird für die aktuell sichtbare Ansicht sein. Spülen, schäumen und wiederholen, und Sie finden Ihre Anwendung aufgrund von Speicherlecks abstürzen. wenn der angegebene Code-Block

In diesem Beispiel flüchtig ist und eine Chance hat, wieder ausgeführt werden (ob wegen Speicher oder einem unbelasteten Blick), würde ich [imgView release]; von dealloc entfernen und nach addSubView verlassen.

Hier ist ein Link zu den grundlegenden behalten/Release Konzepte: http://www.otierney.net/objective-c.html#retain

+0

Dann wird die Bezeichnung ich frage mich, warum Sie eine Implementierung haben.. imgView in der .h-Datei überhaupt? Ich bin ernsthaft gefragt, cos ich bekomme es nicht.Wenn Sie direkt nach der Zuweisung der .image -Eigenschaft loslassen, warum nicht imgView instanziieren, bevor Sie es verwenden? – Jann

+0

Sie sind Für OP ist es wahrscheinlich nicht notwendig. Wird das Bild woanders verwendet? Dann ist es wahrscheinlich notwendig. – nessence

0

(ich genug Ruf add nicht Kommentar noch.)

@bentford: Korrigieren Sie mich, wenn ich falsch liege, aber ich glaube, dass in oder Um den synthetisierten Setter der imgView-Eigenschaft zu verwenden, müssen Sie "self" verwenden.imgView ":

self.imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] 

Wenn Sie nicht über selbst, den Ivar gerade ist verwenden, und es ist nicht die zusätzliche behalten immer

+0

Ich glaube, ich war verwirrt. Ich habe meine Antwort gelöscht, weil sie nicht geholfen hat. Danke für die Rückmeldung. – bentford