UIViewController的生命周期

1. UIViewController的布局過程

VC的生命周期的部分過程 :
viewDidLoad -> viewWillAppear -> updateViewConstraints -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> viewDidAppear -> viewWillDisAppear -> updateViewConstraints -> viewDidDisAppear

對應View的updateConstraints -> layoutSubViews -> drawRect

當view修改約束(addConstraint敞嗡,removeConstraint)會觸發(fā)setNeedsUpdateConstraints许溅,而這個在layoutSubViews之前會觸發(fā)updateConstraints蔬螟,完成之后會調(diào)用layoutSubViews白群。UIViewController在有個updateViewConstraints 方法兄猩,這個方法實際是self.view 被設置了setNeedsUpdateConstraints(第一次展示的時候)炼吴,必然會調(diào)用這個方法(與上面的解釋保持一致了峻仇,第一次可以理解為為self.view增加了各種約束)弓颈。而這個方法的默認實現(xiàn)是調(diào)用子view的updateConstraints方法篮洁,這樣就自上而下的完成了布局涩维。

  • 此處需要注意的地方:
  1. 不要忘記調(diào)用父類的方法,避免有時候出現(xiàn)一些莫名的問題袁波。
  2. 在view的layoutSubViews或者ViewController的viewDidLayoutSubviews方法里后可以拿到view的實際frame瓦阐,所以當我們真的需要frame的時候需要在這個時間點以后才能拿到。
    下面我們可以解釋是為什么viewDidLoad里通過setFrame的方式改過原先在storyboard里拖動的約束代碼無效了篷牌。因為updateViewConstraints在viewDidLoad后執(zhí)行睡蟋,會覆蓋掉之前的設置的frame,所以無效枷颊。

分別打印每個與生命周期相關的代碼戳杀。

// 沒有通過storyBoard(即xib或非xib)調(diào)用這個方法
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        NSLog(@"%s", __func__);
    }
    return self;
}

// 通過storyBoard會調(diào)用這個方法
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
         NSLog(@"%s", __func__);
    }
    return self;
}

// xib加載完成
- (void)awakeFromNib {
    [super awakeFromNib];
         NSLog(@"%s", __func__);
}

// 加載視圖(默認從nib)
- (void)loadView {
    NSLog(@"%s", __func__);
    self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.view.backgroundColor = [UIColor redColor];
}

//視圖控制器中的視圖加載完成,viewController自帶的view加載完成
- (void)viewDidLoad {
    NSLog(@"%s", __func__);
    [super viewDidLoad];
}

//視圖將要出現(xiàn)
- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"%s", __func__);
    [super viewWillAppear:animated];
}

// view 即將布局其 Subviews
- (void)viewWillLayoutSubviews {
    NSLog(@"%s", __func__);
    [super viewWillLayoutSubviews];
}

// view 已經(jīng)布局其 Subviews
- (void)viewDidLayoutSubviews {
    NSLog(@"%s", __func__);
    [super viewDidLayoutSubviews];
}

//視圖已經(jīng)出現(xiàn)
- (void)viewDidAppear:(BOOL)animated {
    NSLog(@"%s", __func__);
    [super viewDidAppear:animated];
}

//視圖將要消失
- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"%s", __func__);
    [super viewWillDisappear:animated];
}

//視圖已經(jīng)消失
- (void)viewDidDisappear:(BOOL)animated {
    NSLog(@"%s", __func__);
    [super viewDidDisappear:animated];
}

//出現(xiàn)內(nèi)存警告  //模擬內(nèi)存警告:點擊模擬器->hardware-> Simulate Memory Warning
- (void)didReceiveMemoryWarning {
    NSLog(@"%s", __func__);
    [super didReceiveMemoryWarning];
}

// 視圖被銷毀
- (void)dealloc {
    NSLog(@"%s", __func__);
}

打印結果

-[ViewController initWithCoder:]
-[ViewController awakeFromNib]
-[ViewController loadView]
-[ViewController viewDidLoad]
-[ViewController viewWillAppear:]
-[ViewController viewWillLayoutSubviews]
-[ViewController viewDidLayoutSubviews]
-[ViewController viewWillLayoutSubviews]
-[ViewController viewDidLayoutSubviews]
-[ViewController viewDidAppear:]
-[ViewController viewWillDisappear:]
-[ViewController viewDidDisappear:]
-[ViewController dealloc]
-[ViewController didReceiveMemoryWarning]
函數(shù) 作用 注意事項
initWithNibName:bundle: 初始化UIViewController夭苗,執(zhí)行關鍵數(shù)據(jù)初始化操作信卡,非StoryBoard創(chuàng)建UIViewController都會調(diào)用這個方法。 不要在這里做view相關操作题造,view在loadView方法中才初始化傍菇。
initWithCoder: 如果使用StoryBoard進行視圖管理,程序不會直接初始化一個UIViewController界赔,StoryBoard會自動初始化或在segue被觸發(fā)時自動初始化桥嗤,因此方法initWithNibName:bundle不會被調(diào)用,但是initWithCoder會被調(diào)用仔蝌。
awakeFromNib 當awakeFromNib方法被調(diào)用時泛领,所有視圖的outlet和action已經(jīng)連接,但還沒有被確定敛惊,這個方法可以算作適合視圖控制器的實例化配合一起使用的渊鞋,因為有些需要根據(jù)用戶洗好來進行設置的內(nèi)容,無法存在storyBoard或xib中,所以可以在awakeFromNib方法中被加載進來锡宋。
loadView 當執(zhí)行到loadView方法時儡湾,如果視圖控制器是通過nib創(chuàng)建,那么視圖控制器已經(jīng)從nib文件中被解檔并創(chuàng)建好了执俩,接下來任務就是對view進行初始化徐钠。
loadView方法在UIViewController對象的view被訪問且為空的時候調(diào)用。這是它與awakeFromNib方法的一個區(qū)別役首。
假設我們在處理內(nèi)存警告時釋放view屬性:self.view = nil尝丐。因此loadView方法在視圖控制器的生命周期內(nèi)可能被調(diào)用多次。
loadView方法不應該直接被調(diào)用衡奥,而是由系統(tǒng)調(diào)用爹袁。它會加載或創(chuàng)建一個view并把它賦值給UIViewController的view屬性。
在創(chuàng)建view的過程中矮固,首先會根據(jù)nibName去找對應的nib文件然后加載失息。如果nibName為空或找不到對應的nib文件,則會創(chuàng)建一個空視圖(這種情況一般是純代碼)
在重寫loadView方法的時候档址,不要調(diào)用父類的方法盹兢。
viewDidLoad 當loadView將view載入內(nèi)存中,會進一步調(diào)用viewDidLoad方法來進行進一步設置守伸。此時蛤迎,視圖層次已經(jīng)放到內(nèi)存中,通常含友,我們對于各種初始化數(shù)據(jù)的載入,初始設定校辩、修改約束窘问、移除視圖等很多操作都可以這個方法中實現(xiàn)。
視圖層次(view hierachy):因為每個視圖都有自己的子視圖宜咒,這個視圖層次其實也可以理解為一顆樹狀的數(shù)據(jù)結構惠赫。而樹的根節(jié)點,也就是根視圖(root view),在UIViewController中以view屬性故黑。它可以看做是其他所有子視圖的容器儿咱,也就是根節(jié)點。
viewWillAppear 系統(tǒng)在載入所有的數(shù)據(jù)后场晶,將會在屏幕上顯示視圖混埠,這時會先調(diào)用這個方法,通常我們會在這個方法對即將顯示的視圖做進一步的設置诗轻。比如钳宪,設置設備不同方向時該如何顯示;設置狀態(tài)欄方向、設置視圖顯示樣式等吏颖。
另一方面搔体,當APP有多個視圖時,上下級視圖切換是也會調(diào)用這個方法半醉,如果在調(diào)入視圖時疚俱,需要對數(shù)據(jù)做更新,就只能在這個方法內(nèi)實現(xiàn)缩多。
viewWillLayoutSubviews view 即將布局其Subviews呆奕。 比如view的bounds改變了(例如:狀態(tài)欄從不顯示到顯示,視圖方向變化),要調(diào)整Subviews的位置瞧壮,在調(diào)整之前要做的工作可以放在該方法中實現(xiàn)
viewDidLayoutSubviews view已經(jīng)布局其Subviews登馒,這里可以放置調(diào)整完成之后需要做的工作。
viewDidAppear 在view被添加到視圖層級中以及多視圖咆槽,上下級視圖切換時調(diào)用這個方法陈轿,在這里可以對正在顯示的視圖做進一步的設置。
viewWillDisappear 在視圖切換時秦忿,當前視圖在即將被移除麦射、或被覆蓋是,會調(diào)用該方法灯谣,此時還沒有調(diào)用removeFromSuperview潜秋。
viewDidDisappear view已經(jīng)消失或被覆蓋,此時已經(jīng)調(diào)用removeFromSuperView;
dealloc 視圖被銷毀胎许,此次需要對你在init和viewDidLoad中創(chuàng)建的對象進行釋放峻呛。
didReceiveMemoryWarning 在內(nèi)存足夠的情況下,app的視圖通常會一直保存在內(nèi)存中辜窑,但是如果內(nèi)存不夠钩述,一些沒有正在顯示的viewController就會收到內(nèi)存不足的警告,然后就會釋放自己擁有的視圖穆碎,以達到釋放內(nèi)存的目的牙勘。但是系統(tǒng)只會釋放內(nèi)存,并不會釋放對象的所有權所禀,所以通常我們需要在這里將不需要顯示在內(nèi)存中保留的對象釋放它的所有權方面,將其指針置nil。

生命歷程

  • [ViewController initWithCoder:][ViewController initWithNibName:Bundle]:首先從歸檔文件中加載UIViewController對象色徘。即使是純代碼恭金,也會把nil作為參數(shù)傳給后者。
  • [UIView awakeFromNib]: 作為第一個方法的助手褂策,方法處理一些額外的設置蔚叨。
  • [ViewController loadView]: 創(chuàng)建或加載一個view并把它賦值給UIViewControllerview屬性床蜘。
  • -[ViewController viewDidLoad]:此時整個視圖層次已經(jīng)放到內(nèi)存中,可以添加修改視圖蔑水,修改約束邢锯,加載數(shù)據(jù)等。
  • [ViewController viewWillAppear:]: 視圖加載完成搀别,并即將顯示在屏幕上丹擎。還沒設置動畫,可以改變當前屏幕方向或狀態(tài)欄的風格等歇父。
  • [ViewController viewWillLayoutSubviews]:即將開始子視圖位置布局
  • [ViewController viewDidLayoutSubviews]:用于通知視圖的位置布局已經(jīng)完成
  • [ViewController viewDidAppear:]:視圖已經(jīng)展示在屏幕上蒂培,可以對視圖做一些關于展示效果方面的修改。
  • [ViewController viewWillDisappear:]:視圖即將消失
  • [ViewController viewDidDisappear:]:視圖已經(jīng)消失'

注意:

  • 只有init系列的方法,如initWithNibName需要自己調(diào)用榜苫,其他方法如loadViewawakeFromNib則是系統(tǒng)自動調(diào)用护戳。而viewWill/Did系列的方法則類似于回調(diào)和通知,也會被自動調(diào)用垂睬。
  • self.view是在loadView方法中創(chuàng)建并建立聯(lián)系的媳荒,如果想要自定義該view,不要調(diào)用[super loadView],并且最后要將自定義的view賦值給self.view。如果該控制器沒有xib文件驹饺,重寫了loadView但沒有做任何事情(也就是self.view為空)钳枕,在viewDidLoad中還使用了self.view(self.view為空時會調(diào)用loadView),這樣會造成死循環(huán)赏壹。
  • 除了initWithNibNameawakeFromNib方法是處理視圖控制器外鱼炒,其他方法都是處理視圖。這兩個方法在視圖控制器的生命周期里只會調(diào)用一次蝌借。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昔瞧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子菩佑,更是在濱河造成了極大的恐慌自晰,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擎鸠,死亡現(xiàn)場離奇詭異,居然都是意外死亡缘圈,警方通過查閱死者的電腦和手機劣光,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來糟把,“玉大人绢涡,你說我怎么就攤上這事∏卜瑁” “怎么了雄可?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我数苫,道長聪舒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任虐急,我火速辦了婚禮箱残,結果婚禮上,老公的妹妹穿的比我還像新娘止吁。我一直安慰自己被辑,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布敬惦。 她就那樣靜靜地躺著盼理,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俄删。 梳的紋絲不亂的頭發(fā)上宏怔,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音抗蠢,去河邊找鬼举哟。 笑死,一個胖子當著我的面吹牛迅矛,可吹牛的內(nèi)容都是我干的妨猩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼秽褒,長吁一口氣:“原來是場噩夢啊……” “哼壶硅!你這毒婦竟也來了?” 一聲冷哼從身側響起销斟,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤庐椒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蚂踊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體约谈,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年犁钟,在試婚紗的時候發(fā)現(xiàn)自己被綠了棱诱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡涝动,死狀恐怖迈勋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情醋粟,我是刑警寧澤靡菇,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布重归,位于F島的核電站,受9級特大地震影響厦凤,放射性物質(zhì)發(fā)生泄漏鼻吮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一泳唠、第九天 我趴在偏房一處隱蔽的房頂上張望狈网。 院中可真熱鬧,春花似錦笨腥、人聲如沸拓哺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽士鸥。三九已至,卻和暖如春谆级,著一層夾襖步出監(jiān)牢的瞬間烤礁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工肥照, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脚仔,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓舆绎,卻偏偏與公主長得像鲤脏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吕朵,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354