Phillip Mills的回答是正確的。這只是它的一個增強。
該系統按記錄工作。
您所看到的viewDidLoad因爲視圖控制器推送到導航控制器是新實例。它必須調用viewDidLoad。
如果你進一步研究,你會發現每個視圖控制器在被彈出時都會被釋放(只需在dealloc中放置一個斷點或NSLog)。這種釋放與視圖控制器容器無關......它不控制它使用的控制器的壽命......它只是對它有強烈的參考。
當控制器從導航控制器堆棧彈出時,導航控制器釋放其引用,並且由於沒有其他引用,視圖控制器將釋放。
導航控制器只保存處於活動堆棧中的視圖控制器的強引用。
如果你想重複使用相同的控制器,你負責重新使用它。當你使用故事板時,你放棄了這個控制(很大程度上)。
比方說,您有一個push
segue來查看控制器Foo
作爲點擊某個按鈕的結果。當點擊該按鈕時,「系統」將創建Foo
(目標視圖控制器)的實例,然後執行搜尋。控制器容器現在擁有對該視圖控制器的唯一強大參考。一旦完成它,VC將會釋放。
由於每次都會創建一個新的控制器,因此每次顯示控制器時都會調用viewDidLoad
。
現在,如果要更改此行爲並緩存視圖控制器供以後重複使用,則必須具體執行此操作。如果你不使用storyboard segues,那很容易,因爲你實際上是在推送/彈出VC到導航控制器。
但是,如果您使用storyboard segues,則會有點麻煩。
有很多方法可以做到,但都需要某種形式的黑客行爲。故事板本身負責實例化新的視圖控制器。一種方法是覆蓋instantiateViewControllerWithIdentifier
。這是當segue需要創建視圖控制器時調用的方法。即使你沒有給出標識符的控制器也會被調用(如果你沒有指定一個標識符,系統會提供一個構成的唯一標識符)。
請注意,我希望這主要是用於教育目的。當然,我並不認爲這是解決問題的最好方法,不管它們是什麼。
喜歡的東西...
@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
現在,你必須使用這個故事板。不幸的是,儘管UIApplication在主要故事板上保留了,但它並沒有公開API來獲取它。但是,每個視圖控制器都有一個方法storyboard
來獲取它創建的故事板。
如果您正在加載自己的故事板,那麼只需實例化MyStoryboard即可。如果您正在使用默認故事板,那麼您需要強制系統使用您的特殊故事板。再次,有很多方法可以做到這一點。一種簡單的方法是覆蓋視圖控制器中的故事板訪問器方法。
您可以讓MyStoryboard成爲將所有內容轉發到Uistoryboard的代理類,或者您可以將主要故事板轉換爲isa-swizzle,或者您可以讓本地控制器從其故事板方法返回一個。
現在,請記住,這裏有一個問題。如果你不止一次地推動堆棧上的同一個視圖控制器會怎麼樣?通過緩存,完全相同的視圖控制器對象將被多次使用。那真的是你想要的嗎?
如果沒有,那麼你現在需要管理與控制容器本身的互動,使他們能夠檢查是否該控制器已經被他們知道,在這種情況下,一個新的實例是必要的。
因此,有是一種方式來獲得緩存控制器,而使用默認的故事板塞格斯(實際上有相當多的方式)...但是,這並不一定是好事,當然不是你在默認情況下會得到什麼。
它在那裏他們談談看法位被卸載的「內存不足」言下之意,他們在默認情況下它是這種情況我還沒有看到四周留有。所以真的取決於父控制器的實現。如果您使用導航控制器,則每次都會創建並加載新的實例。與tabcontrollers不同。 – Imran 2012-08-15 12:58:42
測試低內存行爲(在模擬器上)的一種方法是放置一個視圖控制器,用模態視圖控制器覆蓋它,並使用硬件 - >模擬內存警告選項。隱藏的控制器的視圖應該卸載,然後在模態被取消時重新加載。 – 2012-08-15 14:05:25
oic有趣,生病嘗試。我想任何目前不活躍的視圖都是卸載的候選人。 – Imran 2012-08-15 14:20:36