Die Antwort von Phillip Mills ist korrekt. Dies ist nur eine Verbesserung davon.
Das System funktioniert wie dokumentiert.
Sie sehen viewDidLoad, weil der View-Controller, der auf den Navigationscontroller geschoben wird, eine neue Instanz ist. Es muss viewDidLoad aufrufen.
Wenn Sie etwas weiter nachforschen, würden Sie sehen, dass jeder dieser View-Controller freigegeben wird, wenn sie geclippt werden (setzen Sie einfach einen Breakpoint oder NSLog in dealloc). Diese Freigabe hat nichts mit dem View-Controller-Container zu tun ... sie steuert nicht die Lebensdauer des Controllers, den sie verwendet ... sie enthält nur einen starken Hinweis darauf.
Wenn der Controller vom Navigationssteuerungsstapel entnommen wird, gibt der Nav-Controller seine Referenz frei, und da keine weiteren Verweise darauf vorhanden sind, wird der View-Controller die Zuordnung aufheben.
Der Navigationscontroller enthält nur starke Referenzen zum Anzeigen von Controllern, die sich in seinem aktiven Stapel befinden.
Wenn Sie den gleichen Controller wiederverwenden möchten, sind Sie verantwortlich für die Wiederverwendung. Wenn Sie Storyboard-Übergänge verwenden, geben Sie diese Kontrolle (weitgehend) auf.
Nehmen wir an, Sie haben ein push
Segment, um Controller Foo
als Ergebnis des Tippens einer Schaltfläche anzuzeigen. Wenn diese Schaltfläche angetippt wird, erstellt "das System" eine Instanz von Foo
(der Zielansicht-Controller) und führt dann den Übergang aus. Der Controller-Container enthält jetzt die einzige starke Referenz auf diesen Ansichtscontroller. Sobald es damit fertig ist, wird der VC dealloc.
Da jedes Mal ein neuer Controller erstellt wird, wird viewDidLoad
jedes Mal aufgerufen, wenn der Controller angezeigt wird.
Wenn Sie dieses Verhalten ändern und den View-Controller zur späteren Wiederverwendung zwischenspeichern möchten, müssen Sie dies speziell tun. Wenn Sie keine Storyboard-Übergänge verwenden, ist es einfach, da Sie den VC tatsächlich zum Nav-Controller schieben/poppen.
Wenn Sie jedoch Storyboard-Segmente verwenden, ist es ein bisschen mehr Ärger.
Es gibt eine Reihe von Möglichkeiten, dies zu tun, aber alle erfordern eine Art von Hacking. Das Storyboard selbst ist dafür verantwortlich, neue View-Controller zu instanziieren. Eine Möglichkeit besteht darin, instantiateViewControllerWithIdentifier
zu überschreiben. Das ist die Methode, die aufgerufen wird, wenn ein Segment einen View-Controller erstellen muss. Es wird sogar für Controller aufgerufen, denen Sie keine Kennung zuweisen (das System stellt eine erfundene eindeutige Kennung bereit, wenn Sie keine zuweisen).
Hinweis, ich hoffe, dies ist vor allem für Bildungszwecke. Ich behaupte nicht, dass dies der beste Weg ist, um Ihre Probleme zu lösen, was auch immer sie sein mögen.
So etwas wie ...
@interface MyStoryboard : UIStoryboard
@property BOOL shouldUseCache;
- (void)evict:(NSString*)identifier;
- (void)purge;
@end
@implementation MyStoryboard
- (NSMutableDictionary*)cache {
static char const kCacheKey[1];
NSMutableDictionary *cache = objc_getAssociatedObject(self, kCacheKey);
if (nil == cache) {
cache = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, kCacheKey, cache, OBJC_ASSOCIATION_RETAIN);
}
return cache;
}
- (void)evict:(NSString *)identifier {
[[self cache] removeObjectForKey:identifier];
}
- (void)purge {
[[self cache] removeAllObjects];
}
- (id)instantiateViewControllerWithIdentifier:(NSString *)identifier {
if (!self.shouldUseCache) {
return [super instantiateViewControllerWithIdentifier:identifier];
}
NSMutableDictionary *cache = [self cache];
id result = [cache objectForKey:identifier];
if (result) return result;
result = [super instantiateViewControllerWithIdentifier:identifier];
[cache setObject:result forKey:identifier];
return result;
}
@end
Nun haben Sie das Storyboard verwenden. Während die UIApplication auf dem Haupt-Storyboard gespeichert ist, stellt sie leider keine API bereit, um sie zu erhalten. Jeder View-Controller verfügt jedoch über eine Methode storyboard
, um das Storyboard zu erhalten, aus dem er erstellt wurde.
Wenn Sie Ihre eigenen Storyboards laden, instantiieren Sie MyStoryboard. Wenn Sie das Standard-Storyboard verwenden, müssen Sie das System zwingen, Ihr spezielles Storyboard zu verwenden. Auch hier gibt es viele Möglichkeiten. Eine einfache Möglichkeit besteht darin, die Storyboard-Zugriffsmethode im Ansichtscontroller zu überschreiben.
Sie können MyStoryboard zu einer Proxy-Klasse machen, die alles an UIStoryboard weiterleitet, oder Sie können das Haupt-Storyboard isa-swizzle, oder Sie können Ihren lokalen Controller einfach einen von seiner Storyboard-Methode zurückgeben lassen.
Nun denken Sie daran, es gibt ein Problem hier. Was passiert, wenn Sie denselben View-Controller mehr als einmal auf den Stack schieben? Bei einem Cache wird das exakt gleiche View-Controller-Objekt mehrfach verwendet. Willst du das wirklich?
Wenn nicht, dann müssen Sie jetzt die Interaktion mit den Controller-Containern selbst verwalten, damit sie überprüfen können, ob dieser Controller ihnen bereits bekannt ist. In diesem Fall ist eine neue Instanz erforderlich.
So, ist eine Möglichkeit, zwischengespeicherte Controller zu erhalten, während Standard-Storyboard-Segmente (tatsächlich gibt es viele Möglichkeiten) ... aber das ist nicht unbedingt eine gute Sache, und sicherlich nicht, was Sie standardmäßig erhalten .
Es ist die Bits, wo sie über Ansichten sprechen, die auf 'Niedrigspeicherbedingungen' entladen werden, was impliziert, dass sie standardmäßig herumliegen, was ich nicht als den Fall gesehen habe. Es hängt also wirklich von der Implementierung des übergeordneten Controllers ab. Wenn Sie Navigationscontroller verwenden, wird jedes Mal eine neue Instanz erstellt und geladen. Nicht so mit Tabcontrollern. – Imran
Eine Möglichkeit, das geringe Speicherverhalten (auf dem Simulator) zu testen, besteht darin, einen View-Controller aufzustellen, ihn mit einem Modal View-Controller zu überdecken und die Hardware-> Simulate Memory Warning-Option zu verwenden. Die Sicht des versteckten Controllers sollte entladen und dann erneut geladen werden, wenn der modale Befehl beendet wird. –
oic interessant, krank versuchen, dass. Ich denke, dass jede Ansicht, die momentan nicht aktiv ist, ein Kandidat für das Entladen ist. – Imran