1. 程式人生 > >對應用程式啟動時所有方法的呼叫順序分析

對應用程式啟動時所有方法的呼叫順序分析

一個應用程式的啟動過程要包括代理的建立,控制器的載入和控制器view的載入,這其中有很多關於生命週期的方法,每個方法都是有先後順序的,如果呼叫順序拿不準,或者某段程式碼寫的方法不恰當,就會遇到各種奇葩問題。本文不怕麻煩的在幾乎所有啟動時要呼叫的方法裡都用了 __FUNCTION__ 列印。結果還有有些地方出人意料的

如果你不是在董鉑然部落格園看到本文,請點選檢視原文

首先回顧一下應用程式的啟動過程

①.先載入Main函式

②.在Main函式裡的 UIApplicationMain方法中,建立Application物件 建立Application的Delegate物件

③.建立主迴圈,代理物件開始監聽事件

④.啟動完畢會呼叫 didFinishLaunching方法,並在這個方法中建立UIWindow

⑤.設定UIWindow的根控制器是誰

⑥.如果有storyboard,會根據info.plist中找到應用程式的入口storyboard並載入箭頭所指的控制器

⑦.顯示視窗

本文考慮的時步驟③之後到步驟⑦結束時將要呼叫的方法

其中有AppDelegate,ViewController,MainView(控制器的View),ChildView(子控制元件的View)的18個方法

AppDelegate中的:

1.application:didFinishLaunchingWithOptions:

2.applicationDidBecomeActive:

ViewController中的:

3.loadView

4.viewDidLoad

5.load

6.initialize

7.viewWillAppear

8.viewWillLayoutSubviews

9.viewDidLayoutSubviews

10.viewDidAppear

MainView(控制器的View)中的:

11.initWithCoder(如果沒有storyboard就會呼叫initWithFrame,這裡兩種方法視為一種)

12.awakeFromNib

13.layoutSubviews

14.drawRect

ChildView(子控制元件View)中的:

15.initWithCoder(如果沒有storyboard就會呼叫initWithFrame,這裡兩種方法視為一種)

16.awakeFromNib

17.layoutSubviews

18.drawRect

那麼問題來了,不往下看你可以把上面的十八個方法排個順序麼?

下面的圖是Xcode6.3的beta2版  

有時有變化也就是最後兩個方法有點出入

我更傾向於Xcode 6.1 覺得更科學 下面就是對各個方法的整理

1 + (void)load;

 1.這是應用程式啟動就會呼叫的方法,在這個方法裡寫的程式碼最先呼叫(董鉑然原創)

1 + (void)initialize;

 2.這個是需要用到本類時才呼叫,這個方法裡一般寫 設定導航控制器的主題啊 之類的,如果在後面的方法設定導航欄主題就晚了!(當然在上面的方法裡也能寫)

1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

3.這個方法裡面會建立UIWindow,設定根控制器並展現,比如某些應用程式要載入授權頁面也是在這加,也可以設定觀察者,監聽到通知切換根控制器

1 ChildView - (instancetype)initWithCoder:(NSCoder *)aDecoder;

4.這裡反正我是萬萬沒想到,childView的initwithcoder會在MainView的方法之前呼叫,父的都還沒出來,就先整子控制元件? 有了解比較透徹的博友懇請告訴我謝謝。

1 MainView - (instancetype)initWithCoder:(NSCoder *)aDecoder;

5.就是關於應用程式的資料儲存後的解檔操作。

1 MainView - (void)awakeFromNib;

6.在這個方法裡設定view的背景等一系列普通操作,不要寫關於frame的還不準,在使用IB的時候才會涉及到此方法的使用,當.nib檔案被載入的時候,會發送一個awakeFromNib的訊息到.nib檔案中的每個物件,每個物件都可以定義自己的awakeFromNib函式來響應這個訊息,執行一些必要的操作。 

1 ChildView - (void)awakeFromNib

7.子控制元件也有本方法,重寫父類的方法。基本用法同上 

1 - (void)loadView;

 8.建立檢視的層次結構,這裡需要注意,在沒有建立控制器的view的情況下不能直接寫 self.view 因為self.view的底層是:

if(_view == nil){

  _view = [self loadView]

}

所以這麼寫會直接造成死迴圈。

如果重寫這個loadView方法裡面什麼都不寫,會顯示黑屏。

如果寫了[super view]還要看前面的控制器在建立時是寫的initWithNibName(指定了xib名字),還是寫的普通的init。 如果是後者還是黑屏。

如果不在這個方法中,init的底層是會呼叫initWithNibName的,如果名字是MainViewController,會先在專案中找MainView.xib 找不到會再找MainViewController.xib。 

1 - (void)viewDidLoad;

9.臥槽,這個方法是當年用的最多的方法,但是在之後的開發中就會發現越來越不靠譜,很多東西都還沒載入完畢,各種取值都不準確,很少在這裡面寫東西了。 這裡只是把檢視元件載入完成,還沒有開始佈局不要設定關於 frame 之類的屬性!有時可能會出現差20個畫素點等狀況。

1 - (void)viewWillAppear:(BOOL)animated;

10.檢視將要出現,這個方法用的非常多,比如如果要設定導航欄的setNavigationBarHiden:animate: 就必須要在這裡寫,才能完美契合,不卡跳。 還有很多比如監聽螢幕旋轉啦,

viewWillTransitionToSize:可能要在本方法裡再調一次,或者就是新到這個介面要reloadData或是自動下拉重新整理等 都是寫在本方法裡。

1 - (void)viewWillLayoutSubviews;

11.檢視將要佈局子檢視,蘋果建議的設定介面佈局屬性的方法,這個方法和viewWillAppear裡,系統的底層都是沒有寫任何程式碼的,也就是說這裡面不寫super 也是可以的

1 MainView  - (void)layoutSubviews;

12.在這個方法裡一般設定子控制元件的frame,因為這裡相當於是佈局基本完成了,設定時取到的frame或者是self.bounds才最準,如果在awakeFromeNib裡寫會不準確 。還有這裡要切記千萬不能把super layoutSubviews忘了,可能最後都很難找到這個bug

1 - (void)viewDidLayoutSubviews;

13.這個方法我也是玩玩沒想到,控制器的view的子控制元件還沒有佈局好呢,怎麼這個控制器就已經說佈局全部完成了?那後邊的佈局就不等了? 有獨到見解的也懇請你告訴我,這其中蘋果的意思到底是什麼。 

1 ChildView - (void)layoutSubviews;

14.控制器的子控制元件裡的子控制元件的佈局就在這裡寫了。 

1 MainView - (void)drawRect:(CGRect)rect;

15. 因為預設所有額UI控制元件都是畫上去的,在這一步就是把所有的東西畫上去,有時候需要用到Quartz2D的知識的時候都是在這個方法裡話,但也是要注意別忘了寫super,不然系統原本的東西就都畫不上來了,這裡要建議儘可能使用貝塞爾路徑畫圖形,因為系統預設的那個上下文畫法有時可能會記憶體洩露。drawRect方法只能在載入時呼叫一次,如果後面還需要呼叫,比如下載進度的圓弧,需要一直刷幀,就要使用setNeedsDisplay來定時多次呼叫本方法

1 ChildView - (void)drawRect:(CGRect)rect;

16.view的子控制元件內部的畫圖方法,有時可以自己自定義label 中間帶個刪除線的(用來寫打折前的原價) 就是在這裡畫根線 。

1 - (void)viewDidAppear:(BOOL)animated;

17.把上面的畫圖都畫完了,這裡就會顯示,檢視完全載入完成。在這裡的操作可能就是設定頁面的一些動畫,或者是設定tableView,collectionView,QQ聊天頁面啥的滾動到底部scrollToIndexPath之類的程式碼操作。

1 - (void)applicationDidBecomeActive:(UIApplication *)application;

 18.最後這是AppDelegate的應用程式獲取焦點方法,真正到了這裡,才是所有東西全部載入完畢,應用程式整裝待發保持最佳狀態等待使用者操作。這個方法中一般會寫關於彈出鍵盤的方法,比如有的使用者登入介面為了更好的使用者體驗,就讓你在剛開啟程式來到登入介面的時候,游標的焦點就自動在賬號的文字框裡閃爍,也就是設定賬號文字框為第一響應者。鍵盤在頁面載入完畢後從下方彈出,這種程式碼一般就在本方法寫。

相關推薦

應用程式啟動所有方法呼叫順序分析

一個應用程式的啟動過程要包括代理的建立,控制器的載入和控制器view的載入,這其中有很多關於生命週期的方法,每個方法都是有先後順序的,如果呼叫順序拿不準,或者某段程式碼寫的方法不恰當,就會遇到各種奇葩問題。本文不怕麻煩的在幾乎所有啟動時要呼叫的方法裡都用了 __FUNCT

iOS 應用程式啟動所有方法呼叫順序分析(轉自董鉑然部落格園)

一個應用程式的啟動過程要包括代理的建立,控制器的載入和控制器view的載入,這其中有很多關於生命週期的方法,每個方法都是有先後順序的,如果呼叫順序拿不準,或者某段程式碼寫的方法不恰當,就會遇到各種奇葩問題。本文不怕麻煩的在幾乎所有啟動時要呼叫的方法裡都用了 __FUNCT

Java應用程式執行監控方法(一)——JVMTI的應用

The JVM Tool Interface (JVMTI) 是一個由JVM提供的用於開發針對Java程式開發與監控工具的程式設計介面,通過JVMTI介面(Native API)可以建立代理程式(Agent)以監視和控制 Java 應用程式,包括剖析、除錯、監控

android應用程式啟動短暫白屏或者黑屏的解決處理方案

         最近在研究使用app的過程中發現有的app首次啟動的時候會有短暫的白屏,而有些app則不會出現這樣的情況.起初我以為是手機的問題.但是當我換了幾個手機進行測試的時候仍然會出現這樣的狀況.當然出現白屏這樣的效果肯定是不會給使用者行雲流水般的感覺了,接下來我們

Android App在執行時候按下home鍵 再次進入應用重新啟動的解決方法

如題,這個問題的解決方法跟應用啟動後  從應用市場點選開啟後會重新啟動(相反操作一樣的)的方法是一樣的,,,下面附上解決方法 在專案的啟動第一個FirstActivity的OnCreate()的setContent(R.layout.activity_first)之前加上如下程式

基於對話方塊的MFC程式啟動完全隱藏的簡單方法

如果想基於對話方塊的MFC程式在啟動時就完全隱藏,只在托盤顯示一個圖示,有很多方法可實現,但效果都不理想,總是可以看到對話方塊一閃而過的痕跡。有沒有一個方法徹底的將其隱藏呢,答案是肯定的。這兒有一個簡單的方法實現,效果非常理想,並且只需兩步即可實現。 1.首先要用到的是Mo

WinForm程式啟動不顯示主窗體的5種方法

文中所述WinForm程式啟動時不顯示主窗體的實現方法主要有以下5種,個人覺得第五種最簡單,而且效果也不錯,第四種方法也值得推薦。 實現程式碼及簡短解釋如下://隱藏窗體的方法1/5:不指定任何窗體為主窗體//注意:通常,在一個程式中,關閉主窗體,就可以關閉應用程式。//但是

所有的環境中JDK版本都是1.8,但某個程式啟動是1.7?

今天遇到個很奇怪的問題,公司開發了個eclipse plugin ide,但是啟動時,總顯示一下錯誤: Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurr

Android App在執行時候按下home鍵 再次進入應用重新啟動的解決方法

如題,這個問題的解決方法跟應用啟動後  從應用市場點選開啟後會重新啟動(相反操作一樣的)的方法是一樣的,,,下面附上解決方法在專案的啟動第一個FirstActivity的OnCreate()的setContent(R.

iOS 應用程序啟動要做什麽

通過 有關 撤銷 任務 臨時 hone 分享 ext 後臺 當您的應用程序啟動(無論是在前臺或後臺),使用您的應用程序委托application:willFinishLaunchingWithOptions:和application:didFinishLaunchingWi

android的singleInstance啟動模式及方法呼叫

啟動模式;https://www.cnblogs.com/zhengtu2015/p/5053831.html 1 普及下知識 Activity啟動方式有四種,分別是: standard singleTop singleTask singleInstance 設定Activity

程式啟動log4j報錯 No Log4j 2 configuration file found

ERROR StatusLogger No Log4j 2 configuration file found. Using default configuration (logging only errors to the console), or user programmatically p

SpringBoot 應用程式啟動過程

概述 說到接觸 SpringBoot 伊始,給我第一映像最深的是有兩個關鍵元素: 對照上面的典型程式碼,這個兩個元素分別是: @SpringBootApplication SpringApplication 以及 run() 方法

vs2017 mvc 啟動經常出現呼叫的目標發生異常

1.vs  2017 除錯web 程式時老是出現呼叫的目標發生異常  本人眼拙,基本上看了網站說的一些方法,設定環境變數是無效的,只有一個辦法,解除安裝重灌。 1.0 解除安裝過程 開啟計算機-解除安裝或更改軟體-找到vs2017 ,反鍵解除安裝。 -開啟vs installer

Ionic在應用程式啟動前讀取應用程式啟動之前的配置檔案,避免程式碼頻繁編譯

1.app.module.ts 2.app.config.ts 1.新建app.config.ts檔案 2.內容: import { Inject, Injectable } from '@angular/core'; import { Http } from '@angular/

關於設定MFC應用程式視窗名稱的方法

MFC程式的預設的標題是“無標題-title”,其中title是應用程式的名稱 下面我們以用MFC程式開啟一張指定路徑(D://QINGHUA//DICOM//工業影象.dcm)下面的影象為例 MFC程式的MainFrame類中定義

SpringBoot 應用程式啟動過程探祕

概述 說到接觸 SpringBoot 伊始,給我第一映像最深的是有兩個關鍵元素: 對照上面的典型程式碼,這個兩個元素分別是: @SpringBootApplication SpringApplication 以及 run() 方法 關於 @SpringBootAp

Java 應用程式啟動停止暫停啟動指令碼

#!/bin/sh # Author Pine Chown # date 2018-12-06 # desc 程式啟動暫停指令碼 APP_HOME=/usr/local/java/application #啟動的程式名稱 APP_NAME=charging # 配置檔案生產環境

Android應用程式啟動詳解(二)從原始碼瞭解App的啟動過程

本文承接《Android應用程式啟動詳解(一)》繼續來學習應用程式的啟動的那些事。上文提到startActivity()方法啟動一個app後經過一翻過程就到了app的入口方法ActivityThread.main()。其實我們在之前的文章中《Android的訊息機制(二)之L

.NET下獲取應用程式目錄的一些方法

今天在Console Application下搞了一個小功能,期間需要獲取當前應用程式的根目錄,試了很多方式,都不能直接獲取到,沒有像Server.MapPath()這類的方法來方便地使用。 下面列舉出一些獲取一般目錄的方法:  // 獲取程式的基目錄,結尾包含\ var a = AppDomain