UIViewContorller

iOS對UIViewController生命周期和屬性方法的解析

一、引言

作為MVC設(shè)計模式中的C腕够,Controller一直扮演著項目開發(fā)中最重要的角色,它是視圖和數(shù)據(jù)的橋梁,通過它的管理埃疫,將數(shù)據(jù)有條有理的展示在我們的View層上。iOS中的UIViewController是UIKit框架中最基本的一個類孩哑。從第一個UI視圖到復(fù)雜完整項目栓霜,都離不開UIViewController作為基礎(chǔ)『嵫眩基于UIViewController的封裝和擴展胳蛮,也能夠出色的完成各種復(fù)雜界面邏輯销凑。這篇博客,旨在討論UIViewController的生命周期和屬性方法仅炊,在最基礎(chǔ)的東西上斗幼,往往會得到意想不到的驚喜。

二抚垄、UIViewController的生命周期

要了解UIViewController蜕窿,先要弄清楚其生命周期。在面向?qū)ο蟮恼Z言中呆馁,是對象桐经,就一定要有生命周期,UIViewController也不例外浙滤,生命周期管理Controller的作用范圍和時間阴挣,也管理其內(nèi)對象的作用范圍和時間。首先纺腊,UIViewController中與其生命周期有關(guān)的幾個函數(shù)如下:

//類的初始化方法

+?(void)initialize;

//對象初始化方法

-?(instancetype)init;

//從歸檔初始化

-?(instancetype)initWithCoder:(NSCoder?*)coder;

//加載視圖

-(void)loadView;

//將要加載視圖

-?(void)viewDidLoad;

//將要布局子視圖

-(void)viewWillLayoutSubviews;

//已經(jīng)布局子視圖

-(void)viewDidLayoutSubviews;

//內(nèi)存警告

-?(void)didReceiveMemoryWarning;

//已經(jīng)展示

-(void)viewDidAppear:(BOOL)animated;

//將要展示

-(void)viewWillAppear:(BOOL)animated;

//將要消失

-(void)viewWillDisappear:(BOOL)animated;

//已經(jīng)消失

-(void)viewDidDisappear:(BOOL)animated;

//被釋放

-(void)dealloc;

上面這么多的函數(shù)屯吊,乍一看什么復(fù)雜,其實關(guān)系什么明朗摹菠,除了initialize,init和initWithCoder不是存在所有對象的聲明周期中盒卸,其他函數(shù)都會在UIViewController的聲明周期中有序的被調(diào)用。那么具體的調(diào)用順序是怎樣的呢次氨,最好的辦法是實踐一下蔽介,通過編號打印,結(jié)果如下:

這是一個ViewController完整的聲明周期煮寡,其實里面還有好多地方需要我們注意一下:

1:initialize函數(shù)并不會每次創(chuàng)建對象都調(diào)用虹蓄,只有在這個類第一次創(chuàng)建對象時才會調(diào)用,做一些類的準備工作幸撕,再次創(chuàng)建這個類的對象薇组,initalize方法將不會被調(diào)用,對于這個類的子類坐儿,如果實現(xiàn)了initialize方法律胀,在這個子類第一次創(chuàng)建對象時會調(diào)用自己的initalize方法,之后不會調(diào)用貌矿,如果沒有實現(xiàn)炭菌,那么它的父類將替它再次調(diào)用一下自己的initialize方法,以后創(chuàng)建也都不會再調(diào)用逛漫。因此黑低,如果我們有一些和這個相關(guān)的全局變量,可以在這里進行初始化酌毡。

2:init方法和initCoder方法相似克握,只是被調(diào)用的環(huán)境不一樣蕾管,如果用代碼進行初始化,會調(diào)用init菩暗,從nib文件或者歸檔進行初始化娇掏,會調(diào)用initCoder。

3:loadView方法是開始加載視圖的起始方法勋眯,除非手動調(diào)用婴梧,否則在ViewController的生命周期中沒特殊情況只會被調(diào)用一次。

4:viewDidLoad方法是我們最常用的方法的客蹋,類中成員對象和變量的初始化我們都會放在這個方法中塞蹭,在類創(chuàng)建后,無論視圖的展現(xiàn)或消失讶坯,這個方法也是只會在將要布局時調(diào)用一次番电。

5:viewWillAppear:視圖將要展現(xiàn)時會調(diào)用。

6:viewWillLayoutSubviews:在viewWillAppear后調(diào)用辆琅,將要對子視圖進行布局漱办。

7:viewDidLayoutSubviews:已經(jīng)布局完成子視圖。

8:viewDidAppare:視圖完成顯示時調(diào)用婉烟。

9:viewWillDisappear:視圖將要消失時調(diào)用娩井。

10:viewDidDisappear:視圖已經(jīng)消失時調(diào)用。

11:dealloc:controller被釋放時調(diào)用似袁。

注意:經(jīng)過測試洞辣,從nib文件加載的controller,只要不釋放昙衅,在每次viewWillAppare時都會調(diào)用layoutSubviews方法扬霜,有時甚至會在viewDidAppare后在調(diào)用一次layoutSubviews,而重點是從代碼加載的則只會在開始調(diào)用一次而涉,之后都不會著瓶,所以注意,在layoutSubviews中寫相關(guān)的布局代碼十分危險啼县。

三材原、從storyBoard加載UIViewController實例的傳值陷阱

我們知道,當我們從StoryBoard中加載ViewController時谭羔,我們在Controller中拖拽的視圖是可以被初始化的华糖,這里面有一點需要我們注意麦向,如果我們需要向controller中視圖進行傳值設(shè)置瘟裸,通過以下方法得到的Controller中,視圖還沒有被初始化創(chuàng)建出來:

ViewController2?*?viewController2?=?[[UIStoryboard?storyboardWithName:@"Main"bundle:[NSBundle?mainBundle]]?instantiateViewControllerWithIdentifier:@"ViewController2"];

我們可以在ViewController2的storyBoard中拉一個label诵竭,然后關(guān)聯(lián)到頭文件中话告,如下打印兼搏,會發(fā)現(xiàn)我們得到controller時,里面的視圖對象并沒有進行創(chuàng)建:

ViewController2?*?viewController2?=?[[UIStoryboard?storyboardWithName:@"Main"bundle:[NSBundle?mainBundle]]?instantiateViewControllerWithIdentifier:@"ViewController2"];

NSLog(@"%@",viewController2.label);

[self?presentViewController:viewController2?animated:YES?completion:nil];

打印如下:

可以想象沙郭,如果我們這時候需要對label進行一些屬性設(shè)置佛呻,必然失敗。有人提出可以在創(chuàng)建后病线,手動調(diào)以下loadView方法吓著,我們試一下,結(jié)果如下:

可以看到送挑,手動調(diào)用loadView后绑莺,label是被創(chuàng)建了出來,但是暴漏了一個更嚴重的問題惕耕,系統(tǒng)不在調(diào)用ViewDidLoad方法纺裁,這是十分有風險的,因為我們大部分的初始化代碼都會放在這個方法里司澎,所以手動調(diào)用loadView是一種錯誤的方法欺缘,apple文檔聲明對于loadView方法,我們從來都不要手動直接調(diào)用挤安,那么我們?nèi)绾螌崿F(xiàn)創(chuàng)建后對成員對象進行傳值設(shè)置呢谚殊,iOS9中增加了這樣一個方法:

-?(void)loadViewIfNeeded?NS_AVAILABLE_IOS(9_0);

這個方法十分有用,調(diào)用這個方法蛤铜,會將視圖創(chuàng)建出來络凿,并且不會忽略viewDidLoad的調(diào)用。

在iOS9中昂羡,UIViewController還增加了下面一個布爾值的屬性絮记,可以同來判斷controller的view是否已經(jīng)加載完成:

@property(nullable,?nonatomic,?readonly,?strong)?UIView?*viewIfLoaded?NS_AVAILABLE_IOS(9_0);

四、UIViewController與StroyBoard的相關(guān)相互方法

對于ViewConroller虐先,我們一般有兩種方式創(chuàng)建怨愤,一種是用純代碼的方式,一種是與StoryBoard關(guān)聯(lián)蛹批,在UIViewController中撰洗,有許多方法方便我們與StoryBoard進行交互聯(lián)系。

1腐芍、ViewController直接在StoryBoard中進行跳轉(zhuǎn)的傳值

在StoryBoard中進行界面跳轉(zhuǎn)是十分方便的妓笙,我們在StoryBoard中拉入兩個ViewController肮蛹,在一個上面添加一個按鈕,點住按鈕按住control,將鼠標拉到第二個controller上悟民,會出現(xiàn)如下的跳轉(zhuǎn)選項:

我們選擇一個后,就會在兩個controller之間建立一個跳轉(zhuǎn)連接。當我們運行點擊按鈕后,會自動從第一個controller跳轉(zhuǎn)到第二個controller犀被。在UIViewController中有如下方法可以對是否跳轉(zhuǎn)進行控制:

-?(BOOL)shouldPerformSegueWithIdentifier:(NSString?*)identifier?sender:(nullable?id)sender?NS_AVAILABLE_IOS(6_0);

這個方法如果返回NO,自動跳轉(zhuǎn)將不能進行外冀,會被拒絕寡键,需要注意的是,這個方法只會在自動的跳轉(zhuǎn)時被調(diào)用雪隧,我們手動使用代碼跳轉(zhuǎn)StoryBoard中的連接關(guān)系時是不會被調(diào)用的西轩,我們后面討論。

在執(zhí)行過上述方法后脑沿,如果返回YES遭商,系統(tǒng)還會在執(zhí)行如下一個方法,作為跳轉(zhuǎn)前的準備捅伤,我們可以在這個方法中進行一些傳值操作劫流,這個方法無論使我們手動進行跳轉(zhuǎn)還是storyboard中自動跳轉(zhuǎn),都會被執(zhí)行:

-?(void)prepareForSegue:(UIStoryboardSegue?*)segue?sender:(nullable?id)sender?NS_AVAILABLE_IOS(5_0);

sugur對象中封裝了相關(guān)的ViewController丛忆,可以使用segue.destinationViewController獲取祠汇。

segue在StoryBoard中除了用來自動正向跳轉(zhuǎn)外,我們還可以進行反向的跳轉(zhuǎn)熄诡,類似pop和dismiss方法可很,這種segue被稱為unwind sugue。例如凰浮,我們有一個controller1和一個controllert2我抠,要使用unwind segue從2返回1,我們需要在2中實現(xiàn)如下格式的方法:

-?(IBAction)unwindSegueToViewController:(UIStoryboardSegue?*)segue?{

NSLog(@"unwindSegueToViewController");

}

這個方法中的返回值必須為IBAction袜茧,參數(shù)必須是UIStoryboardSegue菜拓,方法名我們可以自己定義,之后在StoryBoard中的ViewController1中的Exit選項中笛厦,我們會發(fā)現(xiàn)多了一個這樣的方法:

我們可以把它連接到viewController2中的一個按鈕上:

這樣纳鼎,當我們點擊viewController2中的按鈕時,就會返回到我們第一個ViewController1中了裳凸。

當然贱鄙,在使用unwind segue方法時,也是會有一些回調(diào)幫助我們進行跳轉(zhuǎn)前的設(shè)置和傳值姨谷,UIViewController如下方法會在跳轉(zhuǎn)前調(diào)用逗宁,返回NO,則不能進行跳轉(zhuǎn):

4-(BOOL)canPerformUnwindSegueAction:(SEL)action?fromViewController:(UIViewController?*)fromViewController?withSender:(id)sender{

NSLog(@"canPerformUnwindSegueAction");

returnYES;

}

之后會執(zhí)行我們自定義的unwindSegue方法梦湘,這個方法中我們可以什么都不寫瞎颗,模式是會進行跳轉(zhuǎn)的件甥。

2、使用代碼跳轉(zhuǎn)Storyboard中的controller

我們除了在Storyboard中拉拉扯扯可以進行控制器的跳轉(zhuǎn)外言缤,我們也可以使用代碼來跳轉(zhuǎn)Storyboard中segue連接關(guān)系嚼蚀。

在Storyboard中兩個控制器間建立一個segue聯(lián)系禁灼,我們可以取一個名字:

在觸發(fā)跳轉(zhuǎn)的方法中管挟,使用如下方法進行跳轉(zhuǎn),這里面的參數(shù)id就是我們?nèi)〉胹egue的id:

-?(void)performSegueWithIdentifier:(NSString?*)identifier?sender:(nullable?id)sender?NS_AVAILABLE_IOS(5_0);

下面三個屬性我們可以獲取controller的nib文件名弄捕,其storyBoard和其Bundle:

3@property(nullable,?nonatomic,?readonly,?copy)?NSString?*nibName;

@property(nullable,?nonatomic,?readonly,?strong)?NSBundle?*nibBundle;

@property(nullable,?nonatomic,?readonly,?strong)?UIStoryboard?*storyboard?NS_AVAILABLE_IOS(5_0);

五僻孝、UIViewController之間的一些從屬關(guān)系

這部分的內(nèi)容和方法可能我們接觸用到的并不多,但是在某些情況下守谓,使用這些方法可以大大的方便某些邏輯穿铆。

1、parentViewController

UIViewController里面封裝了一個數(shù)組斋荞,可以存放其子ViewController荞雏,系統(tǒng)中使用的例子就是導航和tabBar這類的控制器,我們使用如下方法可以直接訪問這些父的controller:

@property(nullable,nonatomic,weak,readonly)?UIViewController?*parentViewController;

2平酿、模態(tài)跳轉(zhuǎn)中Controller的從屬

在我們進行控制器的跳轉(zhuǎn)時凤优,只要控制器沒有被釋放,我們都可以順藤摸瓜的找到它蜈彼,使用如下兩個方法:

//其所present的contller筑辨,比如,A和B兩個controller幸逆,A跳轉(zhuǎn)到B棍辕,那么A的presentedViewController就是B

@property(nullable,?nonatomic,readonly)?UIViewController?*presentedViewController??NS_AVAILABLE_IOS(5_0);

//和上面的方法剛好相反,比如还绘,A和B兩個controller楚昭,A跳轉(zhuǎn)到B,那么B的presentingViewController就是A

@property(nullable,?nonatomic,readonly)?UIViewController?*presentingViewController?NS_AVAILABLE_IOS(5_0);

了解了上面方法我們可以知道拍顷,對于反向傳值這樣的問題哪替,我們根本不需要代理,block菇怀,通知等這樣的復(fù)雜手段凭舶,只需要獲取跳轉(zhuǎn)到它的Controller,直接設(shè)置即可爱沟。舉個例子帅霜,我們需要在第二個界面消失后,改變第一個界面的顏色呼伸,在第二個controller中只需要下面的代碼即可實現(xiàn):

?

1

2self.presentingViewController.view.backgroundColor?=?[UIColor?colorWithRed:arc4random()%255/255.0?green:arc4random()%255/255.0?blue:arc4random()%255/255.0?alpha:1];

[self?dismissViewControllerAnimated:YES?completion:nil];

六身冀、UIViewController的模態(tài)跳轉(zhuǎn)及動畫特效

單純的UIViewController中钝尸,我們使用最多的是如下的兩個方法,一個向前跳轉(zhuǎn)搂根,一個向后返回:

-?(void)presentViewController:(UIViewController?*)viewControllerToPresent?animated:?(BOOL)flag?completion:(void(^?__nullable)(void))completion?NS_AVAILABLE_IOS(5_0);

-?(void)dismissViewControllerAnimated:?(BOOL)flag?completion:?(void(^?__nullable)(void))completion?NS_AVAILABLE_IOS(5_0);

從方法中珍促,我們可以看到,有animated這個參數(shù)剩愧,來選擇是否有動畫特效猪叙,默認的動畫特效是像抽屜一樣從手機屏幕的下方向上彈起,當然仁卷,這個效果我們可以進行設(shè)置穴翩,UIViewController有如下一個屬性來設(shè)置動畫特效:

@property(nonatomic,assign)?UIModalTransitionStyle?modalTransitionStyle?NS_AVAILABLE_IOS(3_0);

注意,這個要設(shè)置的是將要跳轉(zhuǎn)到的controller锦积,枚舉如下:

typedefNS_ENUM(NSInteger,?UIModalTransitionStyle)?{

UIModalTransitionStyleCoverVertical?=?0,//默認的芒帕,從下向上覆蓋

UIModalTransitionStyleFlipHorizontal?,//水平翻轉(zhuǎn)

UIModalTransitionStyleCrossDissolve,//溶解

UIModalTransitionStylePartialCurl?,從下向上翻頁

};

除了跳轉(zhuǎn)的效果,還有一個屬性可以設(shè)置彈出的controler的填充效果丰介,但是這個屬性只在pad上有效背蟆,在iphone上無效,都是填充到整個屏幕:

@property(nonatomic,assign)?UIModalPresentationStyle?modalPresentationStyle?NS_AVAILABLE_IOS(3_2);

//枚舉如下

typedefNS_ENUM(NSInteger,?UIModalPresentationStyle)?{

UIModalPresentationFullScreen?=?0,//填充整個屏幕

UIModalPresentationPageSheet,//留下狀態(tài)欄

UIModalPresentationFormSheet,//四周留下變暗的空白

UIModalPresentationCurrentContext?,//和跳轉(zhuǎn)到它的控制器保持一致

UIModalPresentationCustom?NS_ENUM_AVAILABLE_IOS(7_0),//自定義

UIModalPresentationOverFullScreen?NS_ENUM_AVAILABLE_IOS(8_0),

UIModalPresentationOverCurrentContext?NS_ENUM_AVAILABLE_IOS(8_0),

UIModalPresentationPopover?NS_ENUM_AVAILABLE_IOS(8_0)?__TVOS_PROHIBITED,

UIModalPresentationNone?NS_ENUM_AVAILABLE_IOS(7_0)?=?-1,

};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哮幢,一起剝皮案震驚了整個濱河市带膀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌家浇,老刑警劉巖本砰,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異钢悲,居然都是意外死亡点额,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門莺琳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來还棱,“玉大人,你說我怎么就攤上這事惭等≌涫郑” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵辞做,是天一觀的道長琳要。 經(jīng)常有香客問我,道長秤茅,這世上最難降的妖魔是什么稚补? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮框喳,結(jié)果婚禮上课幕,老公的妹妹穿的比我還像新娘厦坛。我一直安慰自己,他們只是感情好乍惊,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布杜秸。 她就那樣靜靜地躺著,像睡著了一般润绎。 火紅的嫁衣襯著肌膚如雪撬碟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天凡橱,我揣著相機與錄音小作,去河邊找鬼亭姥。 笑死稼钩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的达罗。 我是一名探鬼主播坝撑,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粮揉!你這毒婦竟也來了巡李?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤扶认,失蹤者是張志新(化名)和其女友劉穎侨拦,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辐宾,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡狱从,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叠纹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片季研。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖誉察,靈堂內(nèi)的尸體忽然破棺而出与涡,到底是詐尸還是另有隱情,我是刑警寧澤持偏,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布驼卖,位于F島的核電站,受9級特大地震影響鸿秆,放射性物質(zhì)發(fā)生泄漏酌畜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一谬莹、第九天 我趴在偏房一處隱蔽的房頂上張望檩奠。 院中可真熱鬧桩了,春花似錦、人聲如沸埠戳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽整胃。三九已至颗圣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屁使,已是汗流浹背在岂。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛮寂,地道東北人蔽午。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像酬蹋,于是被迫代替她去往敵國和親及老。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容