Wann sollte ich Objekte in - (void) viewDidUnload anstatt in -dealloc freigeben?

103

Wofür ist das -(void)viewDidUnloadgut?

Könnte ich nicht einfach alles neu veröffentlichen -dealloc? Wenn die Ansicht entladen würde, würde -deallocsie trotzdem nicht aufgerufen werden?

Vielen Dank
quelle

Antworten:

51

Zusätzlich zu dem, was bereits angedeutet wurde, wollte ich mehr über die Logik dahinter herausarbeiten -viewDidUnload.

Einer der wichtigsten Gründe für die Implementierung ist, dass UIViewControllerUnterklassen üblicherweise auch Verweise auf verschiedene Unteransichten in der Ansichtshierarchie enthalten. Diese Eigenschaften könnten beispielsweise IBOutletsbeim Laden von einer Schreibfeder oder programmgesteuert im Inneren festgelegt worden sein -loadView.

Das zusätzliche Eigentum an Unteransichten UIViewControllerbedeutet, dass selbst wenn ihre Ansicht aus der Ansichtshierarchie entfernt und freigegeben wird, um Speicher zu sparen, wodurch die Unteransichten auch von der Ansicht freigegeben werden, sie tatsächlich nicht freigegeben werden, da die UIViewControllerselbst noch ihre eigene ausstehende enthält Beibehaltung von Verweisen auf diese Objekte. Durch die Freigabe des UIViewControllerzusätzlichen Eigentums an diesen Objekten wird sichergestellt, dass sie auch für den freien Speicher freigegeben werden.

Die Objekte, die Sie hier freigeben, werden normalerweise neu erstellt und erneut festgelegt, wenn die UIViewControllerAnsicht re-loadedentweder von einer Schreibfeder oder über eine Implementierung von stammt -loadView.

Beachten Sie auch, dass die UIViewController viewEigenschaft nilzum Zeitpunkt des Aufrufs dieser Methode gültig ist.

Sean Patrick Murphy
quelle
1
Sie sollten developer.apple.com/library/ios/#featuredarticles/… lesen , um den Lebenszyklus von View / View Controller zu verstehen
Paul Solt
21

Wie die Dokumentation sagt :

Es wird unter Bedingungen mit wenig Arbeitsspeicher aufgerufen, wenn der Ansichtscontroller seine Ansicht und alle mit dieser Ansicht verknüpften Objekte freigeben muss, um Speicher freizugeben.

In der gleichen Situation deallocwird nicht aufgerufen. Diese Methode ist nur in OS3 und höher verfügbar. Der Umgang mit der gleichen Situation in iPhone OS 2.x war ein echtes Problem!

Update Juli 2015 : Es sollte beachtet werden, dass dies viewDidUnloadin iOS 6 veraltet ist, da "Ansichten unter Bedingungen mit geringem Arbeitsspeicher nicht mehr gelöscht werden und diese Methode daher niemals aufgerufen wird." Der moderne Rat ist also, sich keine Sorgen zu machen und zu verwenden dealloc.

Stephen Darlington
quelle
6
Ebenfalls aus den Dokumenten: "Sie sollten dies nur für Objekte tun, die Sie später problemlos neu erstellen können, entweder in Ihrer viewDidLoad-Methode oder aus anderen Teilen Ihrer Anwendung. Sie sollten diese Methode nicht verwenden, um Benutzerdaten oder andere Informationen freizugeben, die nicht verfügbar sind leicht nachgebildet ". Das ist eine Frage, die ich auch selbst hatte, danke!
Leolobato
Was ist, wenn die Ansicht derzeit sichtbar ist? Wäre es nicht schlecht, es wegen einer Warnung zu wenig Speicher fallen zu lassen? ;) dann wäre die App einfach leer leer. Ich kann die Ansicht wegen des geringen Speichers nicht freigeben. Wenn ich keine Ansicht sehe, gebe ich immer den gesamten Controller frei. Trotzdem habe ich einen Root-View-Controller, der intakt bleibt und das Laden / Entladen seiner untergeordneten View-Controller verwaltet ...
Danke
Nein, Sie würden dies nicht verwenden, wenn Sie nur eine Ansicht gegen eine andere austauschen würden. Stellen Sie sich den Fall vor, in dem Sie mit einem UINavigationController einen "Stapel" von Ansichten haben. Es ist nur eine Ansicht sichtbar. Wenn Sie eine Speicherwarnung haben, können Sie alle nicht sichtbaren freigeben.
Stephen Darlington
Wie steuern Sie, dass viewDidUnload in der aktuell sichtbaren Ansicht nicht aufgerufen wird, wie Thanks bemerkt hat?
Arielcamus
1
viewDidUnload wird in der aktuell sichtbaren Ansicht nicht aufgerufen, sondern nur in Ansichten, die nicht sichtbar sind.
Programm
9

Dies liegt daran, dass Sie normalerweise den @propertyals "(nonatomic, retain)"und als solchen festgelegten Setter festlegen, der das aktuelle Objekt freigibt und dann das Argument beibehält, d. H.

self.property = nil;

... macht etwas in der Art von:

[property release];
property = [nil retain];

Daher töten Sie zwei Fliegen mit einer Klappe: Speicherverwaltung (Freigeben des vorhandenen Objekts) und Zuweisen des Zeigers zu Null (da das Senden einer Nachricht an einen Null-Zeiger Null zurückgibt).

Hoffentlich hilft das.

gazzaaa87
quelle
8

Denken Sie daran, dass dies viewDidUnloadeine Methode im Ansichts-Controller ist, nicht in der Ansicht. Die Ansicht dealloc Verfahren werden erhalten , wenn die Ansicht entlädt genannt, aber die Sicht Controller dealloc Verfahren kann erst später genannt werden.

Wenn Sie eine Warnung zu wenig Arbeitsspeicher erhalten und Ihre Ansicht nicht angezeigt wird, was beispielsweise jedes Mal der Fall ist, wenn Sie einen UIImagePickerController verwenden, um dem Benutzer das Fotografieren zu ermöglichen, wird Ihre Ansicht entladen und muss danach neu geladen werden.

David Maymudes
quelle
Das macht Sinn. Was passiert, wenn ich immer den gesamten View Controller ablege? Das mache ich eigentlich. In diesem Fall muss ich mich nicht viel mit -viewDidUnload beschäftigen, oder? Ich hatte noch nie die Situation, dass ich nur die Ansicht fallen ließ, da ich immer den gesamten Controller fallen ließ, wenn er sowieso nicht sichtbar ist.
Danke
Denken Sie daran, dass in einem Fall, in dem Ihre Ansicht angezeigt wird, Sie jedoch eine Vollbildansicht wie den ImagePicker darüber haben, Ihre Ansicht möglicherweise entladen wird, selbst wenn Sie dies nicht geplant haben.
David Maymudes
6

Fazit:

Ansichtscontroller haben eine Ansichtseigenschaft. Normalerweise fügt eine Schreibfeder oder ein Code dieser Ansicht andere Ansichten hinzu. Dies geschieht häufig innerhalb einer -viewDidLoad-Methode wie folgt:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createManyViewsAndAddThemToSelfDotView];
}

Darüber hinaus kann eine NIB-Datei eine Schaltfläche erstellen und an die Ansicht des View Controllers anhängen.

Unter iPhone OS 2.2 mussten Sie beim Aufrufen von -didReceiveMemoryWarning vom System etwas freigeben, um Speicherplatz freizugeben. Sie können die Ansicht des gesamten View Controllers freigeben, wenn dies sinnvoll ist. Oder einfach nur große speicherintensive Inhalte.

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

In dem neuen Betriebssystem 3.0 gibt es jetzt eine -viewDidUnload-Methode, die vom System aufgerufen wird, wenn die Ansicht aufgrund des geringen Arbeitsspeichers entladen wurde (bitte korrigieren Sie mich: Wann genau wird dies aufgerufen?)

-viewDidUnload wird verwendet, um alle Objekte freizugeben, die sowohl dem View Controller selbst als auch der View gehörten. Der Grund: Wenn ein Ansichtscontroller Verweise auf untergeordnete Elemente der Ansicht enthält, z. B. eine Schaltfläche, werden die referenzierten untergeordneten Ansichten nicht freigegeben, da ihre Aufbewahrungsanzahl> = 1 ist. Nachdem sie in -viewDidUnload freigegeben wurden, können sie freigegeben werden aus dem Gedächtnis.

Vielen Dank
quelle
1
remeber in view wurde entladen, um self.button = nil;, not [button release]; zu tun.
mk12
6

Apple hat viewWillUnload abgelehnt. Jetzt sollten Sie didReceiveMemoryWarning oder Dealloc verwenden, um Ihre Objekte freizugeben.

In iOS 6 sind die Methoden viewWillUnload und viewDidUnload von UIViewController jetzt veraltet. Wenn Sie diese Methoden zum Freigeben von Daten verwendet haben, verwenden Sie stattdessen die didReceiveMemoryWarning-Methode. Mit dieser Methode können Sie auch Verweise auf die Ansicht des Ansichtscontrollers freigeben, wenn diese nicht verwendet wird. Sie müssen zuvor testen, ob sich die Ansicht nicht in einem Fenster befindet.

Guilherme Torres Castro
quelle
5

Wenn der Ansichtscontroller aus dem Navigationscontrollerstapel entfernt und an keiner anderen Stelle beibehalten wird, wird er freigegeben und anstelle von viewDidUnload wird die Freigabe aufgerufen. Sie sollten die in loadView erstellten Ansichten in dealloc freigeben, es ist jedoch nicht erforderlich, die Variablen auf nil zu setzen, da die Variablen kurz nach dem Aufruf von dealloc nicht mehr vorhanden sind.

Colin
quelle
3

Sie können alle Unteransichten freigeben, an denen Sie festhalten, z. B. die UIImageView, die Sie in Ihrer loadView-Methode beibehalten haben, oder besser das Bild, das sich in dieser UIImageView befand.

drvdijk
quelle