2012-02-04 142 views
18

當用戶切換到另一個程序後又返回時,原始程序的視圖將被另一個程序的新視圖替換。所以當用戶切換回原來的程序時,viewDidLoad會被第二次調用嗎?viewDidLoad多久調用一次?

我問這個,因爲如果是這種情況,那麼放置在viewDidLoad中的初始化代碼將在用戶每次來回切換屏幕時執行。而這可能會導致正在重置的意見和失去用戶的未完成的作品...

+0

感謝您的評論。 – Stanley 2012-02-04 01:31:15

+4

評論是不正確的。每次你的視圖控制器的視圖被加載時,它都會被調用,而不僅僅是第一次。 – 2012-02-04 01:35:43

+0

感謝您的更正... – Stanley 2012-02-04 01:48:51

回答

26

不要在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中再次取消它們。

viewDidLoadviewDidUnload想象爲像視圖控制器的視圖屬性的init/dealloc。對於與視圖相關的內容,請在這些方法中創建並釋放它。對於與控制器本身相關的內容,請在initWithNibNamedealloc中創建並釋放它。

UPDATE:在iOS 6和後,viewDidUnload不會被調用任何更多(除非視圖被明確設置爲nil中的代碼),等等viewDidLoad通常只進行一次在一個視圖控制器的壽命稱爲。這使得建議不太重要,但這仍然是最佳實踐,如果您需要支持iOS 5及更早版本,仍然是必要的。

更新2:如果您加載從故事板視圖控制器(也就是現在推薦的做法),而不是編程方式創建它,然後initWithNibName:bundle:不會被調用。改爲使用initWithCoder:awakeFromNib來初始化您的控制器。

+0

感謝您的詳細解答... – Stanley 2012-02-04 01:29:52

+0

您說:「這種方法是在視圖從筆尖加載之前調用」,什麼是「this」是指「initWithNibName」還是「viewDidLoad」? – Stanley 2012-02-04 01:39:14

+0

道歉,我澄清了它。 – 2012-02-04 01:45:12

3

the docs:視圖控制器加載其相關的意見到內存後

該方法被調用。

所以,只要視圖控制器將其視圖加載到內存中,就會調用它。這可能是第一次的看法是加載永不再,或每看法變得可見時,如果你的觀點不斷地卸載(viewDidUnload由於內存限制等)

+0

感謝您的回答... - – Stanley 2012-02-04 01:26:47

4

-viewDidLoad將被調用一次,每當視圖控制器需要加載其視圖層次結構。顯然,這將在控制器首次訪問其視圖時發生。如果視圖控制器稍後卸載其視圖,則在下次加載視圖時將再次調用-viewDidLoad。視圖控制器不會因爲隱藏視圖而卸載其視圖,但如果內存開始變慢,它可能會這樣做。

視圖控制器應該知道其視圖的狀態,並且可以根據需要在其-viewDidLoad方法中設置它們。不應該使用視圖來存儲狀態 - 不應該因爲視圖被卸載而不可挽回地丟失。

+1

感謝您的詳細解答... – Stanley 2012-02-04 01:26:11

+0

關於「視圖控制器應該知道其視圖的狀態」,希望問這種「保持狀態的能力」是我們的風俗責任代碼還是內置在Cocoa庫中? – Stanley 2012-02-04 01:46:13

+1

它不是內置的。關鍵是你的視圖控制器不應該依靠視圖來保持狀態。例如,如果您的視圖中有一個滑塊,則視圖控制器應該在其更改時記住該滑塊的值。這樣,如果視圖被卸載然後再次加載,視圖控制器可以將滑塊重置爲-viewDidLoad中保存的值。 – Caleb 2012-02-04 02:28:48

5

那麼當用戶切換回原來的程序時,會第二次調用 viewDidLoad?

(以上是從OP)

在這種情況下,有兩種方法被稱爲:

- (void)applicationWillEnterForeground:(UIApplication *)application; 

重新打開轉到後臺運行的應用程序(從任務管理器或跳板再次)
解鎖設備,該應用程序處於活動狀態時被鎖定。

- (void)applicationDidBecomeActive:(UIApplication *)application 

後打電話
通知中心解僱
任務管理器撤職(雙擊Home鍵&雙再次點擊)

+0

感謝您的詳細解答... – Stanley 2012-02-04 01:30:20

17

@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 
+0

感謝您的詳細解答... – Stanley 2012-02-04 02:08:25

+1

您應該真的添加一個viewDidUnload樣本到您的很好的例子。 – Till 2012-02-05 14:38:15

+0

@謝謝你的提示。我忘記了包含viewDidUnload。固定。 – 2012-02-05 15:29:04