IOS viewDidLoad方法被執行兩次(viewDidLoad和loadView方法詳解)
為了搞清楚viewDidLoad、loadView等方法的用途和調用順序,寫了一個小demo,不料viewDidLoad方法被執行了兩次,模擬器也一直是黑屏。查看了這兩個方法的官方解釋後找到了錯誤原因和解決方案。
首先來看UIViewController.h檔案中對viewDidLoad方法的解釋:
- (void)viewDidLoad; // Called after the view has been loaded. For view controllers created in code, this is after -loadView. For view controllers unarchived from a nib, this is after the view is set.
接下來是對loadView方法的解釋:
- (void)loadView; // This is where subclasses should create their custom view hierarchy if they aren't using a nib. Should never be called directly.
無論是從xib檔案中載入視圖,還是自己建立視圖,viewDidLoad方法都會被調用,而且都是在視圖已經被載入後調用,所以這裡可以明確的一點是,任何UI控制項的建立都不應該在viewDidLoad方法中被實現,因為這是xib檔案或者loadView方法的任務。viewDidLoad只是通過nib或者loadView方法載入視圖的一周拓展和補充機制,比如一些不方便通過nib設定的屬性或是臨時需要進行處理的控制項內容。
至於loadView方法和xib檔案的關係,個人的理解是:真正的UI控制項的建立,都是要通過調用loadView中的代碼來實現的,只不過在xib檔案中,這些代碼以xml格式的文檔被儲存,並且蘋果通過storyboard解析這個xml文檔,形成了一個可視化的圖形介面。這是兩者的共同點,至於不同點,官方文檔中的解釋已經很清楚了,一旦調用了loadView方法就意味著不是用nib檔案。這就意味著loadView和xib檔案不相容。loadView具有更高的優先順序。
下面通過幾個實驗來證明以上觀點。
實驗1:
建立一個空的工程檔案,在viewDidLoad函數中寫入簡單的一行代碼:
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"123");}
實驗結果:運行程式後發現:控制台輸出一行結果“123”。模擬器顯示一個純白色的介面。
實驗分析:控制台的結果非常容易理解。但是我們並沒有建立一個UIView或者設定它的背景顏色,系統是怎麼建立我們在模擬器中看到的內容的呢?
答案是,如果我們不實現loadView方法,系統會預設我們不適用自訂的方式建立view而是從nib檔案中載入。這時候就回去storyboard或者其他相應的nib檔案中去尋找載入視圖的代碼。由於預設的ViewController類在main.storyboard中有自己的nib檔案,所以可以成功的載入一個UIView。
實驗2:
實現一個空的loadView方法:
- (void)loadView{}
實驗結果:運行程式後發現,控制台輸出兩行“123”,模擬器黑屏。
實驗分析:模擬器黑屏非常容易理解,因為我們實現了loadView方法,編譯器以為我們要自訂一個UIView對象,從而去執行loadView方法中的代碼,試圖建立一個UIView,但是顯然這樣做會失敗,所以得到一個黑色的(沒有任何內容)的介面。至於為什麼viewDidLoad方法會被調用兩次,原因並不清楚(希望讀到此處的大牛留言指教)。
實驗三:
實現完整的loadView方法:
- (void)loadView{ self.view = [[ UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame]; self.view.backgroundColor = [UIColor whiteColor];}
實驗結果:同實驗1的結果
實驗分析:實現了一個完整的UIView的建立過程,與通過nib檔案建立非常類似。
通過以上幾個實驗得出以下結論:
1.如果想要通過自訂的代碼建立UIView,把這些代碼都寫入loadView方法裡面去。
2.希望通過nib檔案建立UIView的話,不要重寫loadView方法。
3.viewDidLoad方法被執行兩次很有可能是重寫了一個不完整的loadView方法導致的 。