9、iOS應用界面切換(筆記知識源:Geekband & 網易云課堂,同時包括各類網上資源的查找)

iOS應用界面切換

  • 1、UIViewController 的生命周期;
  • 2、push & pop;
  • 3、presentModalView. (它是和 navigationController 無關的,是在所在的 viewController 添加一個模態 view)

iOS三種則視圖切換的原理各不相同 (from:Kenshin Cui's Blog)

  • UITabBarController: 以平行的方式管理視圖,各個視圖之間往往關系不大,每個加入到UITabBarController的視圖都會進行初始化,即使當前不顯示在界面上這兩句現在還不是很懂,相對比較占用內存優化的一個入口嗎?。[tabBarItem 的 image 屬性必須是png格式(建議32*32)并且打開alpha通道,否則無法正常顯示]
  • UINavigationController: 以棧的方式管理視圖,各個視圖的切換就是壓棧和出棧操作,出棧后的視圖會立即銷毀釋放比較合適。[只有在棧頂的控制器能夠顯示在界面中。UINavigationController默認也不會顯示任何視圖,它必須有一個根控制器rootViewController,而且這個根控制器不會像其他子控制器一樣會被銷毀。]
  • UIModalController: 以模態窗口的形式管理視圖,當前視圖關閉前,無法在其它的視圖上進行操作。
    對其blog進行研讀并在以后做好筆記工作

(接下來先了解2和3的內容)
下面的代碼了解push & pop 和 presentModalView 的方法。
在實現文件 .m 的 viewDidLoad 方法中輸入以下代碼:

"1號“代碼段

UIBotton  *pushButton = [UIButton buttonWithType: UIButtonTypeCustom];
pushButton.frame = CGRectMake(10, 74, self.view.bounds.width - 20, 44);
[pushButton setBackgroundColor: [UIColor cyanColor]];
[pushButton setTittle: @"push a view" forState: UIControlStateNormal];
[pushButton setTitleColor: [UIColor blackColor] forState: UIControlStateNormal];
[pushButton addTarget: self
               action: @selector(pushButtonClicked)
     forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: pushButton];                          

接下來創建一個 presentButton,目的是為了演示 兩種不同的頁面切換方式:

“2號”代碼段

UIBotton  *presentButton = [UIButton buttonWithType: UIButtonTypeCustom];
presentButton.frame = CGRectMake(10, 130, self.view.bounds.width - 20, 44);
[presentButton setBackgroundColor: [UIColor yellowColor]];
[presentButton setTittle: @"present a modal view" forState: UIControlStateNormal];
[presentButton setTitleColor: [UIColor blackColor] forState: UIControlStateNormal];
[presentButton addTarget: self
               action: @selector(presentButtonClicked)
     forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: presentButton];                          

上面有兩段 選擇器 selector 的代碼。通過它們使界面進行跳轉,不過首先要選定跳轉到哪一個頁面,在選定之后,在實現文件 .m 開頭導入跳轉后界面的控制器才會在執行方法后可以顯示界面:

“3號”代碼段

#import  "BLSubViewController.h"

接下來,先介紹下 push 操作:它類似于 UINavigationController 的壓棧(先進后出)。下面演示上面兩個 Button 所關聯的 selector 跳轉方法,第一個介紹的是 push (注意它們要跳轉到的那個頁面已經選定,就是剛導入的 BLSubViewController):

“4號”代碼段

#pragma mark - Custom event methods

- (void)pushButtonClicked:(id)sender
{
    BLSubViewController *subViewController = [[BLSubViewController] init];
    [self.navigationController pushViewController:subViewController animated:YES];
}

也許在 animated: 中使用 YES 顯得更貼近自然語言吧。
??上面方法中的兩行代碼就已經通過 push 將頁面進行了跳轉。 [首先創建了一個跳轉目的界面的視圖控制器,然后由當前界面視圖控制器 push 到 目的地視圖控制器
??上面的一個代碼段介紹了 push 的方法,在跳轉到 BLSubViewController 的界面之后,我們如果這時需要跳回到剛才那個頁面,其時就是將剛剛押入的棧彈出(所謂的pop方法)。[其實,蘋果已經幫我們在BLSubViewController 的界面設置了跳轉回去的按鈕,如下圖:

左上角的 One 就是返回的控件

現在,我們需要自己來做一個 pop 回去,這樣才算知道所以然.
??首先第一步和前面設置兩個 button 控件一樣的,先在 BLSubViewController 的界面 復制一樣的代碼,改掉相關的代碼,selector 方法名 設置為:backButtonClicked:

“5號”代碼段

- (void)backButtonClicked:(id)sender
{
    [self.navigationController popViewControllerAnimated:YES];
}

只方法中的一行代碼就將其移除了。
??值得注意的是在 navigationController 中還為我們提供了另一個可以返回指定 UIViewController 的方法(所以它本身也是一個數組對象 NSArray):
**NSArray popToViewController:(UIViewController ) animated:(BOOL)
還有一個是返回 rootViewController:
NSArray popToRootViewControllerAnimated:(BOOL)
一般是上面代碼段中的方法更加普遍使用,我個人認為比較中庸,但也實在。后面兩個方法則是比較有針對性。


上面我們將文章一開頭的 界面切換 中的第二點 push & pop 講完了,現在來講講第三點 presentModalView。modalView是一個模態窗口(模態的你只能在該窗口進行操作,否則就是非模態窗口),它是蓋在其它視圖之上的。現在我們來完成 2號代碼段 中的 selector :

- (void)presentButtonClicked:(id)sender
{
    BLSubViewController *subViewController = [[BLSubViewController alloc] init];
    [self presentViewController:subViewController animated:YES completion:nil];

    // 第二行代碼中 self presentViewController:  由這個方法可以感知到,presentModalView 確實就是覆蓋其上的一個視圖控制器。
}

設置好之后,跳轉后畫面如下,presentModalView 即圖中右邊視圖。注意 presentViewController:subViewController animated:YES completion:nil 是蘋果的一個新方法,它代替了舊方法,當我們使用新方法的時候需要注意它是支持哪個版本的,根據自己項目的受眾群體進行合理的設置,以免造成使用舊版系統的用戶的應用崩潰。

presentModalView.jpg

??左邊顯示的是 push 之后的界面,右邊顯示的是模態窗口。此時,在模態窗口中點擊 back 是不會有任何反應的,因為此時在 BLSubViewController 中的 navigationController 的值是 nil。那么,問題來了,當進入這個模態窗口之后我們點擊 back 是無效的,我們該如何退出這個窗口呢?我們需要使 back 生效,修改 “5號”代碼段

“6號”代碼段

- (void)backButtonClicked:(id)sender
{
    if (self.navigationController) {
        [self.navigationController popViewControllerAnimated:YES];
    } else {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

這里使用了 ' dismissViewControllerAnimated: completion: '。至此,點擊模態窗口的 back 按鈕就可以相應并跳轉回原先的界面了。 同時界面切換的第三點也講完了。


接下來,我們需要了解界面切換的第一點 UIViewController 的生命周期
我們看到先在 BLSubViewController.m 文件中設置這些代碼段:

#pragma mark - Memory management methods
......
#pragma mark - View's lifecycle methods
......
#pragma mark - Custom event methods
......

這樣這個項目中的各個BL...ViewController.m 實現文件中的結構就是由這樣三個代碼塊構成的。在 View's lifecycle methods 中的方法 - (void)viewDidLoad{} 和 - (void)viewDidUnload{} 其實都不止調用一次。例如:

界面1.jpg

??在上圖中,下面的五個 tabbar 點擊其中一個就跳轉到點擊方的界面,這樣該界面就被 viewDidLoad 了一次。 蘋果的做法很聰明,一般,只有等你點擊了下面其中一個之后,系統才會調用加載那一個視圖控制圖。當出現內存不夠的情況(例子:在點擊并加載第三個視圖的時候用模擬器模擬內存警告的情況),前面調用加載的 one 和 two 視圖 會調用 - (void)didReceiveMemoryWarning {} 方法,接著會調用 - (void)viewDidUnload {} 的方法(現在這個方法已經不被蘋果使用,當然你可以自己設置),當調用了這個方法,此方法所在的 試圖控制器就會被釋放(比如先打開了one->two->three, 到 three 出現內存警告,three的圖片不會被釋放,因為用戶正在使用,不過為了內存空間 one & two 就會被釋放)。然后再次點擊 one 或者 two 視圖 ,它們會再次調用 - (void)viewDidLoad {} 的方法。
??因此根據上面的理論結合實踐的論述,當在運行app的時候,會根據不同的手機,以及手機不同的內存情況,系統有可能會不止一次的調用 - (void)viewDidLoad {} 和 - (void)viewDidUnload {} 方法。
??不過需要說明的是這個流程只在 iOS 6 之前是存在的。在 iOS 6 之后 - (void)viewDidUnload {} 是被棄用了。不過,我們花這么大的篇幅來介紹,是有助于了解 iOS 的內存是如何進行管理的。
??那現在我們的疑問是,蘋果為什么會棄用這個內存管理方法呢?在聽課的我也帶著這個苦惱,還好蘋果給出了解釋:因為當我們為了內存空間 調用了 - (void)viewDidUnload {} 的方法,是將這個 view 給置 空 了, 但這其時并沒有為內存留出多少空間,這個view所占用的空間其實是很小的,所以便廢棄了。 好吧,似乎是很有道理,不過我也不知道是哪里更占用所謂更多的內存。 不過有一點明確的是,以前在 - (void)viewDidUnload {} 中做的事情,就需要在 - (void)didReceiveMemoryWarning {} 中進行操作。
??在 iOS6 之后,當內存釋放的情況,在這個 viewDidLoad 中的view 并不會被置空,所以我們可以理解為,在那之后 - (void)viewDidLoad {} 方法只會被調用一次。

7 號代碼段

#pragma mark - Memory management methods

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];

    if (self.view.window == nil) {

    }
}

- (void)dealloc
{
}

這之后,當應用收到了內存不夠的警告后,需要在- (void)didReceiveMemoryWarning {}方法中做上述代碼段中的判斷,只有當 self.view.window 等于空的時候,才在里面輸入你要釋放的一些內容(圖片等數據,即同時注意不要將用戶在使用的界面view給釋放了!)。


emsp;上面講的是內存釋放的一些流程,現在接下來再繼續講生命周期的內容,看下面一般完整的生命周期代碼段:

8 號代碼段

#pragma mark - View's lifecycle methods

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

當我們在主界面選擇點擊 push a view 跳轉到 BLSubViewController 后,會先后調用 代碼塊8 的前三個方法,當我們在 BLSubViewController 中點擊 back 按鈕,就會依次調用后兩個方法,并在離開此界面的同時,可能會進行一些釋放或者存儲的功能,這樣還會調用到 7號代碼段的 - (void)dealloc{}方法。
??上述講的就是我們所說的 UIViewController 的生命周期。


這是第一篇完整的使用 Markdown 來寫的一篇筆記,同時一篇認真的筆記的完成確實是很耗費時間的,但在耗費時間的同時也發現,這樣對于理解的深入是很有幫助的。

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

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,170評論 4 61
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,727評論 25 708
  • 在五千年的歷史星河之中,有一些時光剪影里的碎片,它們穿越了不同的時空,連接了不同的時代,它們是浩瀚長河之中皎...
    我沒有朗姆酒閱讀 289評論 0 0
  • 那些夢想,再不做就只有后悔了 我不知道你是否有和我一樣的感受,有很多想法,可是卻一直拖著沒做,忽然有一天,當別人和...
    影寧寧閱讀 264評論 0 1
  • 生活中總有那么一個人,一件事,甚至一個微小的舉動就能感動到你,也能讓你找到曾經的自己。 2017年8月1日 星...
    陳筱柒閱讀 417評論 6 3