當用戶切換到另一個程序後又返回時,原始程序的視圖將被另一個程序的新視圖替換。所以當用戶切換回原來的程序時,viewDidLoad會被第二次調用嗎?viewDidLoad多久調用一次?
我問這個,因爲如果是這種情況,那麼放置在viewDidLoad中的初始化代碼將在用戶每次來回切換屏幕時執行。而這可能會導致正在重置的意見和失去用戶的未完成的作品...
當用戶切換到另一個程序後又返回時,原始程序的視圖將被另一個程序的新視圖替換。所以當用戶切換回原來的程序時,viewDidLoad會被第二次調用嗎?viewDidLoad多久調用一次?
我問這個,因爲如果是這種情況,那麼放置在viewDidLoad中的初始化代碼將在用戶每次來回切換屏幕時執行。而這可能會導致正在重置的意見和失去用戶的未完成的作品...
不要在viewDidLoad
做視圖控制器初始化。這是一個常見的錯誤。
對於東西是加載視圖控制器時,應該只發生一次,做到在控制器的init方法,像這樣:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil
{
if ((self = [super initWithNibName:nibNameOrNil bundle:bundleOrNil]))
{
//do your initialisation here
}
return self;
}
的initWithNibName:bundle:
方法被稱爲之前的畫面從加載筆尖,並且在視圖控制器的使用壽命中僅調用一次。
控制器的視圖可以在控制器的使用壽命期間多次加載和卸載,並且每次都會調用。只要不在屏幕上,它可能會被卸載,通常如果內存不足的話。
如果你設置了viewDidLoad
(例如,以編程方式添加子視圖)的東西,你應該總是在viewDidUnload
中再次取消它們。
將viewDidLoad
和viewDidUnload
想象爲像視圖控制器的視圖屬性的init/dealloc。對於與視圖相關的內容,請在這些方法中創建並釋放它。對於與控制器本身相關的內容,請在initWithNibName
和dealloc
中創建並釋放它。
UPDATE:在iOS 6和後,viewDidUnload
不會被調用任何更多(除非視圖被明確設置爲nil中的代碼),等等viewDidLoad
通常只進行一次在一個視圖控制器的壽命稱爲。這使得建議不太重要,但這仍然是最佳實踐,如果您需要支持iOS 5及更早版本,仍然是必要的。
更新2:如果您加載從故事板視圖控制器(也就是現在推薦的做法),而不是編程方式創建它,然後initWithNibName:bundle:
不會被調用。改爲使用initWithCoder:
或awakeFromNib
來初始化您的控制器。
-viewDidLoad
將被調用一次,每當視圖控制器需要加載其視圖層次結構。顯然,這將在控制器首次訪問其視圖時發生。如果視圖控制器稍後卸載其視圖,則在下次加載視圖時將再次調用-viewDidLoad
。視圖控制器不會因爲隱藏視圖而卸載其視圖,但如果內存開始變慢,它可能會這樣做。
視圖控制器應該知道其視圖的狀態,並且可以根據需要在其-viewDidLoad
方法中設置它們。不應該使用視圖來存儲狀態 - 不應該因爲視圖被卸載而不可挽回地丟失。
那麼當用戶切換回原來的程序時,會第二次調用 viewDidLoad?
(以上是從OP)
在這種情況下,有兩種方法被稱爲:
- (void)applicationWillEnterForeground:(UIApplication *)application;
重新打開轉到後臺運行的應用程序(從任務管理器或跳板再次)
解鎖設備,該應用程序處於活動狀態時被鎖定。
- (void)applicationDidBecomeActive:(UIApplication *)application
後打電話
通知中心解僱
任務管理器撤職(雙擊Home鍵&雙再次點擊)
感謝您的詳細解答... – Stanley 2012-02-04 01:30:20
@Nick洛克伍德提供優秀的信息,但也有一些事情要記住。
首先,如果視圖控制器是從nib文件或故事板實例化的,則不會調用initWithNibName:bundle:
。在這種情況下,調用initWithCoder:
和awakeFromNib
。這種情況在iOS上有點不常見,但隨着故事板的增加,現在視圖控制器繞過initWithNibName:bundle:
更爲常見。
我建議把非UI初始化代碼在一個單獨的方法(我稱之爲我的setup
)和來自initWithNibName:bundle:
和awakeFromNib
調用它。但是,只有在初始化只運行一次非常重要的時候,我纔會這樣做。否則,我把它放在viewWillAppear:
儘可能延遲加載。其次,你不應該做任何在init...
或awakeFromNib
中引用self.view
的東西。你永遠不應該參考self.view
,直到調用viewDidLoad
(否則你會強制nib文件比需要的更早加載)。與UI有關的事情應該在viewDidLoad
(如果它們與設置視圖有關)或viewWillAppear:
(如果它們與配置視圖(即,用數據加載它們)有關)。
所以我的方式通常設置這些東西了:
@implementation
- (void)setup {
// Non-UI initialization goes here. It will only ever be called once.
}
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle {
if ((self = [super initWithNibName:nibName bundle:bundle])) {
[self setup];
}
return self;
}
- (void)awakeFromNib {
[self setup];
}
- (void)viewDidLoad {
// Any UI-related configuration goes here. It may be called multiple times,
// but each time it is called, `self.view` will be freshly loaded from the nib
// file.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Set all IBOutlets to `nil` here.
// Drop any lazy-load data that you didn't drop in viewWillDisappear:
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Most data loading should go here to make sure the view matches the model
// every time it's put on the screen. This is also a good place to observe
// notifications and KVO, and to setup timers.
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// Unregister from notifications and KVO here (balancing viewWillAppear:).
// Stop timers.
// This is a good place to tidy things up, free memory, save things to
// the model, etc.
}
- (void)dealloc {
// standard release stuff if non-ARC
[[NSNotificationCenter defaultCenter] removeObvserver:self]; // If you observed anything
// Stop timers.
// Don't unregister KVO here. Observe and remove KVO in viewWill(Dis)appear.
}
@end
感謝您的評論。 – Stanley 2012-02-04 01:31:15
評論是不正確的。每次你的視圖控制器的視圖被加載時,它都會被調用,而不僅僅是第一次。 – 2012-02-04 01:35:43
感謝您的更正... – Stanley 2012-02-04 01:48:51