La risposta di Phillip Mills è corretta. Questo è solo un miglioramento di esso.
Il sistema funziona come documentato.
Stai visualizzando viewDidLoad perché il controller di visualizzazione inserito nel controller di navigazione è una nuova istanza . È deve chiamare viewDidLoad.
Se si analizza un po 'più avanti, si vedrà che ciascuno di questi controller di vista viene deallocato quando vengono spuntati (basta inserire un breakpoint o un NSLog in dealloc). Questa deallocazione non ha nulla a che fare con il contenitore del controller di visualizzazione ... non controlla la vita del controller che usa ... sta solo mantenendo un forte riferimento ad esso.
Quando il controller viene estratto dallo stack del controller di navigazione, il controller nav rilascia il suo riferimento e poiché non vi sono altri riferimenti ad esso, il controller della vista verrà dealloc.
Il controller di navigazione contiene solo forti riferimenti per visualizzare i controller che si trovano nella pila attiva.
Se si desidera riutilizzare lo stesso controller, è il riutilizzo. Quando si utilizza lo storyboard, si rinuncia a tale controllo (in larga misura).
Supponiamo di avere un push
seguito per visualizzare il controller Foo
come risultato del tocco di un pulsante. Toccando questo pulsante, "il sistema" creerà un'istanza di Foo
(il controller della vista di destinazione), quindi eseguirà il seguito. Il contenitore del controller ora contiene l'unico riferimento forte a quel controller di visualizzazione. Una volta terminato, il VC sarà dealloc.
Poiché ogni volta che crea un nuovo controller, viewDidLoad
verrà chiamato ogni volta che viene presentato il controller.
Ora, se si desidera modificare questo comportamento e memorizzare nella cache il controller di visualizzazione per un successivo riutilizzo, è necessario farlo in modo specifico. Se non si utilizza segues storyboard, è facile dal momento che si sta effettivamente spingendo/popping il VC al controller nav.
Se, tuttavia, si utilizza lo storyboard, è un po 'più difficile.
Ci sono diversi modi per farlo, ma tutti richiedono una qualche forma di hacking. Lo storyboard stesso è incaricato di creare istanze di nuovi controller di visualizzazione. Un modo è quello di ignorare instantiateViewControllerWithIdentifier
. Questo è il metodo che viene chiamato quando un seguito deve creare un controller di visualizzazione. Si chiama anche per i controller a cui non si attribuisce un identificatore (il sistema fornisce un identificativo univoco inventato se non ne assegni uno).
Nota, spero che questo sia principalmente per scopi didattici. Certamente non sto suggerendo questo come il modo migliore per risolvere i tuoi problemi, qualunque essi siano.
Qualcosa di simile ...
@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
Ora, è necessario utilizzare questo storyboard. Sfortunatamente, mentre UIApplicazione mantiene lo storyboard principale, non espone un'API per ottenerlo. Tuttavia, ciascun controller di visualizzazione ha un metodo, storyboard
per ottenere lo storyboard da cui è stato creato.
Se si stanno caricando i propri storyboard, è sufficiente istanziare MyStoryboard. Se si utilizza lo storyboard predefinito, è necessario forzare il sistema a utilizzare quello speciale. Ancora una volta, ci sono molti modi per farlo. Un modo semplice consiste nell'override del metodo accessor dello storyboard nel controller della vista.
È possibile rendere MyStoryboard una classe proxy che inoltra tutto a UIStoryboard, oppure è possibile isa-swizzle lo storyboard principale, oppure è sufficiente che il controller locale ne restituisca uno dal metodo storyboard.
Ora, ricorda, c'è un problema qui. Cosa succede se si spinge lo stesso controller di visualizzazione sullo stack più di una volta? Con una cache, lo stesso identico oggetto del controller di visualizzazione verrà utilizzato più volte. E 'davvero quello che vuoi?
Se no, allora è ora necessario gestire l'interazione con i contenitori del controller stessi in modo che possano controllare per vedere se questo controller è già noto da loro, nel qual caso una nuova istanza è necessario.
Quindi, non v'è un modo per ottenere i controllori nella cache durante l'utilizzo segues predefinita storyboard (in realtà ci sono alcuni modi) ... ma che non è necessariamente una buona cosa, e certamente non quello che si ottiene per default .
sua i bit dove si parla di vista di essere scaricati su che implica 'condizioni di scarsa memoria' sono lasciati in giro da default che non ho visto essere il caso. Quindi in realtà dipende dall'implementazione del controller genitore. Se si utilizzano i controller di navigazione, ogni volta viene creata e caricata una nuova istanza. Non così con i tabcontroller. – Imran
Un modo per testare il comportamento della memoria bassa (sul simulatore) è di mettere su un controller di vista, coprirlo con un controller di vista modale, e utilizzare il Hardware-> opzione di avviso di memoria Simula. La vista del controllore nascosto dovrebbe scaricare e quindi ricaricare quando il modale viene rimosso. –
oic interessante, mal provatelo. Immagino che qualsiasi vista che al momento non sia attiva è quindi candidata per lo scarico. – Imran