iOS開發(fā)之UIViewController

對于初學(xué)者來說往往無法弄清iOS中各種各樣的Controller之間的關(guān)系和使用場景。這篇文章將嘗試整理各個Controller的用法以及注意事項柠衅。

主要介紹的Controller有:

  • UIViewController
  • UINavigationController
  • UITabBarController
  • ModalViewController
  • ChildViewController

UIXXXController之間的關(guān)系

對于各個Controller之間的關(guān)系我想從下圖開始講解:

img
img

程序的入口是main()這個大家都知道待侵,iOS也不例外也是在main
里面:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

對于這個main里面干了什么事情與這篇文章的主題不太符合斯辰,初學(xué)者可能也不太能理解八回,感興趣的可以去了解一下runloop,我們只要知道在這之后扇商,我們的APP將要執(zhí)行的類就到了AppDelegate,并且我們的代碼也是從這里開始宿礁。

與我們今天主題最相關(guān)的就是下面一段了:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.rootViewController = [[UIViewController alloc] init];
    [self makeKeyAndVisible];
    return YES;
}

這段代碼設(shè)置就是iOS程序里啟動后顯示的第一個ViewController案铺,接下來的流程就全由你自己控制了。

PS:在Xcode5 之后默認(rèn)使用storyboard不需要在這里寫任何代碼就會有顯示默認(rèn)的ViewController梆靖,那時因為在info.plist中選擇使用Main.storyboard的initialViewController作為初始ViewController控汉。

對于一個iOS的APP來講第一個UIViewController的類型是非常重要的,它將決定這個APP的UI架構(gòu)和層級返吻。

我們就從Xcode自帶的3個典型模板工程去分析和講解姑子。

img
img

如圖,Xcode創(chuàng)建工程時有幾組模板工程可以選擇:Master-Detail Application测僵、Single View Application街佑、Tabbed Application。其中創(chuàng)建后對應(yīng)的rootViewController分別為:

  • Master-Detail Application ---> UINavigationController
  • Single View Application ---> UIViewController
  • Tabbed Application ---> UITabbarController

PS:Page-Based Application在今天的主題中暫不討論

UINavigationController

使用方法

//初始化
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[CustomViewController new]];

//在vc中使用
[self.navigationController pushViewController:vc animated:YES];

視圖跳轉(zhuǎn)

UINavigationController實際可以理解為UIViewController的一個棧捍靠,有著先進(jìn)后出的特點沐旨,操作過程中我們一般也是使用的push和pop進(jìn)行操作。

pushViewController:animated:

popViewControllerAnimated:

popToRootViewControllerAnimated:

popToViewController:animated:

在這一塊需要注意的是我們使用的self.navigationController剂公,在實際使用中我們都應(yīng)該是在UIViewController(UINavigationController棧里面的)來調(diào)用該方法希俩,這個屬性值最初就是在setRootController時系統(tǒng)設(shè)置的,然后在每一次push過程中傳遞纲辽。然后在push和pop這一塊沒什么好說的了颜武。

視圖區(qū)域

img
img

如圖,紅色線框區(qū)域為navigationController.view的范圍區(qū)域拖吼,藍(lán)色區(qū)域為navigationController當(dāng)前棧頂?shù)腢IViewController的視圖區(qū)域鳞上,黃色區(qū)域就是后面我們要講的NavigationBar的區(qū)域。

由圖可以看出UIViewController是處于UINavigationController內(nèi)吊档,并覆蓋在navigationController.view上的篙议,在我們push和pop操作過程中實際上更改的內(nèi)容僅僅是UIViewController區(qū)域的內(nèi)容,所以你在任何棧內(nèi)的viewController使用navigationController.view操作,之后的結(jié)果是不會隨著push和pop改變的鬼贱。

在這里你還需要注意UINavigationController的幾個屬性:

topViewController   //返回UINavigationController棧頂?shù)膙iewController

visibleViewController //返回UINavigationController可見到的viewController 包括ModalViewController

viewControllers //返回UINavigationController棧里面的所有viewController移怯,以NSArray形式返回

topViewController與visibleViewController區(qū)別在于,如果當(dāng)前棧頂?shù)氖莢iewController1这难,然后在這個Controller中使用presentViewController以Modal方式彈出viewController2舟误。topViewController返回的是viewController1,visibleViewController返回的則是viewController2姻乓。

UITabbarController

對于UITabbarController這就沒什么好說的了嵌溢,使用就真的是簡單。

UITabBarController *tabBarViewController = [[UITabBarController alloc]init];
[self.window setRootViewController:tabBarViewController];    
FirstViewController* first = [[FirstViewController alloc]init];
SecondViewController* second = [[SecondViewController alloc]init];
tabBarViewController.viewControllers = [NSArray arrayWithObjects:first, second,nil];

更詳細(xì)信息見:官方文檔

ChildViewController

今天的重點在于這一塊了蹋岩,首先我們拋出一個問題:

如何在一個ViewController中創(chuàng)建和管理多個復(fù)雜的子View赖草?

在許多剛?cè)腴T或者是初學(xué)者來說對于這種情況的處理方法就是addSubView,需要多少個子視圖不停添加進(jìn)去就對了剪个。那么問題來了秧骑,

  • 產(chǎn)生代碼量龐大而且邏輯復(fù)雜的ViewController,看著一個上千行代碼的ViewController是不是想死的心都有了扣囊?
  • 產(chǎn)生的大量<nonatomic,strong>UIView占據(jù)的高內(nèi)存如何處理腿堤?

處理addSubView這個方法,還有一種誤用就是:

[self.view addSubView:self.vc.view];

直接添加ViewController的view到當(dāng)前ViewController的view中如暖,這種方法倒是可以代碼的高耦合的問題笆檀,但是這種方法會產(chǎn)生一系列更加嚴(yán)重的問題:

  • 直接add進(jìn)去的SubView不在ViewController的view hierarchy內(nèi),事件不會正常傳遞盒至,如:旋轉(zhuǎn)酗洒、觸摸等,屬于危險操作
  • 違背CocoaTouch開發(fā)的設(shè)計MVC原則枷遂,ViewController應(yīng)該且只應(yīng)該管理一個view hierarchy

這也不行那也不可以樱衷,我們到底需要怎么來用呢?addChildViewController才是我們需要的酒唉。

addChildViewController是在iOS5之后出現(xiàn)的矩桂,在這之前人們一直都在忍受著上面我們講的種種陣痛。首先我們看看具體用法:

[self addChildViewController:newVC];
//[newVC willMoveToParentViewController:self];
[self.view addSubview:newVC.view];
[newVC didMoveToParentViewController:self];

[oldVC willMoveToParentViewController:nil];
[oldVC.view removeFromSuperview];
[oldVC removeFromParentViewController]; 
//[oldVC didMoveToParentViewController:nil];

上面代碼中寫出了添加和移除ChildViewController的具體寫法痪伦,添加過程:

  1. 通過addChildViewController:添加子控制器
  2. 這一步為隱式調(diào)用侄榴,系統(tǒng)在addChildViewController:方法后會自動調(diào)用方法willMoveToParentViewController:
  3. 將子控制器視圖添加進(jìn)主視圖
  4. 通知子控制器childViewController添加完成,這一步需要手動顯示調(diào)用

移除過程與之相反网沾,只是調(diào)用的幾個方法名不一樣癞蚕。

在Apple官方文檔上明確表示了必須要調(diào)用didMoveToParentViewController和willMoveToParentViewController方法來確認(rèn)完成過程執(zhí)行完畢,初學(xué)者需要特別注意和幾個方法的調(diào)用順序辉哥,使用不當(dāng)會導(dǎo)致UIViewControllerHierarchyInconsistency的警告桦山。

介紹了使用方法攒射,在來介紹一下使用它的好處,好處就是規(guī)避了上面提到的兩種誤用產(chǎn)生的后果恒水,具體就是:

  1. 解決了代碼的高耦合
  2. 系統(tǒng)在收到內(nèi)存警告的時候會回收一些并未顯示的view会放,釋放內(nèi)存
  3. 這種方式add進(jìn)入的view是屬于當(dāng)前view hierarchy內(nèi),可以正常傳遞各種事件钉凌。

在使用addChildViewController:還有一個比較高級的特性就是可以由自己選擇控制childViewController的Appearance callbacks鸦概。

//該方法返回NO則childViewController不會自動viewWillAppear和viewWillDisappear對應(yīng)的方法
- (BOOL)shouldAutomaticallyForwardAppearanceMethods
{
    return NO;
}
//viewWillAppear調(diào)用設(shè)置為YES,viewWillDisappear調(diào)用設(shè)置為NO
[self.customChildViewController beginAppearanceTransition:YES animated:animated];
//對應(yīng)的DidAppear調(diào)用需要成對出現(xiàn)
[self.customChildViewController endAppearanceTransition];

這一篇關(guān)于UIViewController的介紹就寫到這里了就結(jié)束了甩骏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市先慷,隨后出現(xiàn)的幾起案子饮笛,更是在濱河造成了極大的恐慌,老刑警劉巖论熙,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件福青,死亡現(xiàn)場離奇詭異,居然都是意外死亡脓诡,警方通過查閱死者的電腦和手機无午,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祝谚,“玉大人宪迟,你說我怎么就攤上這事〗还撸” “怎么了次泽?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長席爽。 經(jīng)常有香客問我意荤,道長,這世上最難降的妖魔是什么只锻? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任玖像,我火速辦了婚禮,結(jié)果婚禮上齐饮,老公的妹妹穿的比我還像新娘捐寥。我一直安慰自己,他們只是感情好祖驱,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布上真。 她就那樣靜靜地躺著,像睡著了一般羹膳。 火紅的嫁衣襯著肌膚如雪睡互。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機與錄音就珠,去河邊找鬼寇壳。 笑死,一個胖子當(dāng)著我的面吹牛妻怎,可吹牛的內(nèi)容都是我干的壳炎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼逼侦,長吁一口氣:“原來是場噩夢啊……” “哼匿辩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起榛丢,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤铲球,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后晰赞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體稼病,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年掖鱼,在試婚紗的時候發(fā)現(xiàn)自己被綠了然走。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡戏挡,死狀恐怖芍瑞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情褐墅,我是刑警寧澤啄巧,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站掌栅,受9級特大地震影響秩仆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜猾封,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一澄耍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晌缘,春花似錦齐莲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至岳枷,卻和暖如春芒填,著一層夾襖步出監(jiān)牢的瞬間呜叫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工殿衰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留朱庆,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓闷祥,卻偏偏與公主長得像娱颊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子凯砍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

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

  • /* UIViewController is a generic controller base class th...
    DanDanC閱讀 1,811評論 0 2
  • 本文的Demo工程代碼參考這里的StudyUIViewAndUIVC 目錄 加載初始化loadViewviewDi...
    諾之林閱讀 3,134評論 0 6
  • 7箱硕、不使用IB是,下面這樣做有什么問題悟衩? 6剧罩、請說說Layer和View的關(guān)系,以及你是如何使用它們的局待。 1.首先...
    AlanGe閱讀 673評論 0 1
  • 活動準(zhǔn)備了大半個月,突然被叫停菱属,原因是我們的活動與另一個舉辦單位的活動有沖突钳榨,恰巧另一個舉辦單位是我們活動場地的提...
    蘇穆涼閱讀 345評論 0 0
  • 沒有什么不可錯過 沒有什么不能抓住 機緣巧合,因緣際會 擦肩而過的纽门, 是因為它本就不屬于你 機會薛耻, 其實并不會垂青...
    一個壺閱讀 91評論 0 0