UI篇-VC的生命周期以及UIView的layoutSubviews和drawRect方法

前言

看似常用的UIView,其實有很多不經常用到的方法和應該注意的機制,我是一個喜歡打破砂鍋問到底的人,可是很多問題在網上搜索不到答案,大部分的博客都是轉載相同的東西,所以我自己就新建 Dome,實際測試了一些數據,得到了一些有用的東西,分享給大家,其中也用到了其它大神的理論和指點,在此感謝。


viewController的生命周期

  • 單個viewController的生命周期

    initWithCoder:(NSCoder *)aDecoder:(如果使用storyboard或者xib)
    loadView:#加載view 會多次調用并且會使viewWillLayoutSubviews、viewDidLayoutSubviews不再執行
    viewDidLoad:view加載完畢
    viewWillAppear:控制器的view將要顯示,
    viewWillLayoutSubviews:控制器的view將要布局子控件
    viewDidLayoutSubviews:控制器的view布局子控件完成
    viewDidAppear:控制器的view完全顯示
    viewWillDisappear:控制器的view即將消失的時候
    viewDidDisappear:控制器的view完全消失的時候
    
  • 多個viewControllers跳轉

    當我們點擊push的時候首先會加載下一個界面然后才會調用界面的消失方法
    initWithCoder:(NSCoder *)aDecoder:ViewController2 (如果用xib創建的情況下)
    loadView:ViewController2
    viewDidLoad:ViewController2
    viewWillDisappear:ViewController1 將要消失
    viewWillAppear:ViewController2 將要出現
    viewWillLayoutSubviews ViewController2
    viewDidLayoutSubviews ViewController2
    viewWillLayoutSubviews:ViewController1
    viewDidLayoutSubviews:ViewController1
    viewDidDisappear:ViewController1 完全消失
    viewDidAppear:ViewController2 完全出現
    
  • 小結:
    整個控制器聲明周期: viewDidLoad -> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> viewDidAppear -> viewWillDisappear -> viewDidDisappear

  • 說明

viewWillLayoutSubviews 在 viewWillAppear 之后 viewDidAppear 之前執行,這個方法會被調用多次,如果在此創建視圖,可能會創建多個,而且這個方法中執行耗時操作依然會造成跳轉卡頓的問題。
一個VC 在執行viewWillDisappear 或者viewDidDisappear 方法時都是出棧之后才執行的,也就是說 已經不在 self.navigationController 的viewControllers中了,而一個 VC 執行viewWillAppear 時必定是 self.navigationController 的 topViewController即棧頂的視圖。
一個很常見的問題,我們需要在VC被銷毀的時候處理一些事情,可是 viewWillDisappear 不管是入棧新的視圖還是出棧當前視圖都會被調用,無法判斷,結合我之前說的原理,我們可以利用下面這個方法判斷當前VC是否是被出棧了。
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:YES];
if ([[self.navigationController viewControllers] containsObject:self ]) {
NSLog(@"TwoViewController 暫時消失");
}else
{
NSLog(@"TwoViewController 出棧了");
}
}

首先需要特別說明的一點是:

在使用 VC繪制UI的時候,它不同于 UIView,UIView中 init方法調用后,UIView就已經繪制好(初始化好了)。

但是在VC中,當前UIView的是在 viewDidLoad 執行后才初始化好的,所以我們會見到這樣一個Bug,在VC初始化語句后面調用 一個 VC的繪制UI的方法,你會發現根本沒有效果,這就是因為,VC中跟試圖的初始化是需要時間的,你在VC根試圖初始化之前調用繪制UI的方法當然是不會有效果出現的。

UIView的setNeedsDisplay和setNeedsLayout方法。

首先兩個方法都是異步執行的。setNeedsDisplay會調用 drawRect方法,這樣可以拿到UIGraphicsGetCurrentContext,就可以畫畫。
setNeedsLayout會默認調用layoutSubViews,就可以處理子視圖中的一些數據。

綜上兩個方法都是異步執行的,layoutSubviews方便數據計算,drawRect方便視圖重繪。UIView中方法的執行順序大概是這樣的:

init 方法 >>屬性的set/get 方法>> layoutSubviews(當然是要達到觸發條件)>>drawRect, 使用得當可以在View的調用中起到很好的效果。

layoutSubviews在以下情況下會被調用:

1、init初始化不會觸發layoutSubviews。
2、addSubview會觸發layoutSubviews。
3、設置view的Frame會觸發layoutSubviews,當然前提是frame的值設置前后發生了變化。
4、滾動一個UIScrollView會觸發layoutSubviews。
5、旋轉Screen會觸發父UIView上的layoutSubviews事件。
6、改變一個UIView大小的時候也會觸發父UIView上的layoutSubviews事件。
7、直接調用setLayoutSubviews。

drawRect在以下情況下會被調用:

 1、如果在UIView初始化時沒有設置rect大小,將直接導致drawRect不被自動調用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 兩方法之后掉用的.所以不用擔心在 控制器中,這些View的drawRect就開始畫了.這樣可以在控制器中設置一些值給View(如果這些View draw的時候需要用到某些變量 值).
 2、該方法在調用sizeToFit后被調用,所以可以先調用sizeToFit計算出size。然后系統自動調用drawRect:方法。
 3、通過設置contentMode屬性值為UIViewContentModeRedraw。那么將在每次設置或更改frame的時候自動調用drawRect:。
 4、直接調用setNeedsDisplay,或者setNeedsDisplayInRect:觸發drawRect:,但是有個前提條件是rect不能為0。以上1,2推薦;而3,4不提倡

drawRect方法使用注意點:

1、 **若使用UIView繪圖,只能在drawRect:方法中獲取相應的contextRef并繪圖。如果在其他方法中獲取將獲取到一個invalidate 的ref并且不能用于畫圖**。**drawRect:方法不能手動顯示調用,必須通過調用setNeedsDisplay 或 者 setNeedsDisplayInRect,讓系統自動調該方法。強行調用也不會起作用的。**
2、**若使用calayer繪圖,只能在drawInContext: 中(類似魚drawRect)繪制**,或者在delegate中的相應方法繪制。同樣也是調用setNeedDisplay等間接調用以上方法
3、**若要實時畫圖,不能使用gestureRecognizer,只能使用touchbegan等方法來掉用setNeedsDisplay實時刷新屏幕。**

值得注意的是:

viewWillAppear 嚴謹的說應該是視圖將要達到棧頂時調用,不是每次視圖出現在屏幕時就會調用,一個很常見的現象是,home鍵后,再次啟動程序,第一個出現的頁面的 viewWillAppear 是不回被調用的。

setNeedsDisplay和setNeedsLayout 詳解

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容