iOS的SDK中提供不少原生ViewController,大大提升了咱們的開發效率,下面是個人一些經驗。編程
1、結構xcode
按結構能夠對iOS的全部ViewController分紅兩類:app
一、主要用於展現內容的ViewController,這種ViewController主要用於爲用戶展現內容,並與用戶交互,如UITableViewController,UIViewController。函數
二、用於控制和顯示其餘ViewController的ViewController。這種ViewController通常都是一個ViewController的容器。如UINavigationController,UITabbarController。它們都有一個屬性:viewControllers。其中UINavigationController表示一種Stack式結構,push一個ViewController或pop一次,所以後一個ViewController會依賴前一個ViewController。而UITabbarController表示一個Array結構,各個ViewController是並列的。性能
第一種ViewController會常常被繼承,用來顯示不一樣的數據給用戶。而第二種不多被繼承,除非你真的須要自定義它。學習
注:細心的同窗應該能發現,在xcode中新建一個ViewController時,只能夠繼承自UIViewController和UITableViewController,而它們都是第一種。動畫
圖1ui
2、Controller和View的生命週期atom
這裏指的View是指Controller的View。它做爲Controller的屬性,生命週期在Controller的生命週期內。就是說你的Controller不能在view釋放前就釋放了。spa
圖2 ViewController生命週期
當你alloc並init了一個ViewController時,這個ViewController應該是尚未建立view的。ViewController的view是使用lazyInit方式建立,就是說你調用的view屬性的getter:[self view]。在getter裏會先判斷view是否建立,若是沒有建立,那麼會調用loadView來建立view。loadView完成時會繼續調用viewDidLoad。loadView和viewDidLoad的一個區別就是:loadView時尚未view。而viewDidLoad時view以及建立好了。
當view被添加其餘view中以前時,會調用viewWillAppear,而以後會調用viewDidAppear。
當view從其餘view中移出以前時,會調用viewWillDisAppear,而以後會調用viewDidDisappear。
當view不在使用,並且時disappeared,受到內存警告時,那麼viewController會將view釋放並其指爲nil。
3、代碼組織(如何設計良好的viewController)
ViewController生命週期中有那麼多函數,一個重要問題就是什麼代碼該寫在什麼地方。
一、init裏不要出現建立view的代碼。良好的設計,在init裏應該只有相關數據的初始化,並且這些數據都是比較關鍵的數據。init裏不要掉self.view,不然會致使viewcontroller建立view。(由於view是lazyinit的)。
二、loadView中只初始化view,通常用於建立比較關鍵的view如tableViewController的tabView,UINavigationController的navgationBar,不可調用view的getter(在調super loadView前),最好也不要重載這個方法。
三、viewDidLoad 這時候view已經有了,最適合建立一些附加的view和控件了。有一點須要注意的是,viewDidLoad會調用屢次(viewcontroller可能屢次載入view,參見圖2)。
四、viewWillAppear 這個通常在view被添加到superview以前,切換動畫以前調用。在這裏能夠進行一些顯示前的處理。好比鍵盤彈出,一些特殊的過程動畫(好比狀態條和navigationbar顏色)。
五、viewDidAppear 通常用於顯示後,在切換動畫後,若是有須要的操做,能夠在這裏加入相關代碼。
六、viewDidUnload 這時候viewController的view已是nil了。因爲這通常發生在內存警告時,因此在這裏你應該將那些不在顯示的view釋放了。好比你在viewcontroller的view上加了一個label,並且這個label是viewcontroller的屬性,那麼你要把這個屬性設置成nil,以避免佔用沒必要要的內存,而這個label在viewDidLoad時會從新建立。
在我以前的學習筆記中討論過ViewController,過了這麼久,對它也有了新的認識和體會,ViewController是咱們在開發過程當中碰到最多的朋友,今天就來好好認識一下它。ViewController是iOS開發中MVC模式中的C,ViewController是view的controller,ViewController的職責主要包括管理內部各個view的加載顯示和卸載,同時負責與其餘ViewController的通訊和協調。在iOS中,有兩類ViewController,一類是顯示內容的,好比UIViewController、UITableViewController等,同時還能夠自定義繼承自UIViewController的ViewController;另外一類ViewController容器,UINavigationViewController和UITabBarController等,UINavigationController是以Stack的形式來存儲和管理ViewController,UITabBarController是以Array的形式來管理ViewController。和Android中Activity同樣,iOS開發中,ViewController也有本身的生命週期(Lifecycle)。
首先來看看View的加載過程,以下圖:
從圖中能夠看到,在view加載過程當中首先會調用loadView方法,在這個方法中主要完成一些view的初始化工做,好比UINavigationViewController和UITabBarController等容器類的ViewController;接下來就是加載view,加載成功後,會接着調用viewDidLoad方法,這裏要記住的一點是,在loadview以前,是沒有view的,也就是說,在這以前,view尚未被初始化。完成viewDidLoad方法後,ViewController裏面就成功的加載view了,如上圖右下角所示。
在Controller中建立view有兩種方式,一種是經過代碼建立、一種是經過Storyboard或Interface Builder來建立,後者能夠比較直觀的配置view的外觀和屬性,Storyboard配合iOS6後推出的AutoLayout,應該是Apple以後主推的一種UI定製的解決方案,後期我會專門介紹一篇使用AutoLayout進行UI製做的文章。言歸正傳,經過IB或Storyboard建立view,在Controller中建立view後,會在Controller中對view進行一些操做,會出現以下代碼:
這裏用IBOutlet標記了一個UIButton和一個UITextField,用IBAction來標記UIButton的響應事件,IBOutlet和IBAction都是一個整形常量,用來標記控件,經過一張圖能比較清晰的看清他們之間的關係:
上圖中,MyViewController是繼承自UIViewController的一個自定義ViewController,它包含兩個view,一個是UIButton,一個是UITextField,從箭頭的指向性上就能夠較好的理解IBOutlet和IBAction了。IBOutlet是告訴Interface Builder,此實例變量被鏈接到nib文件中的view對象,IBOutlet自己不作任何操做,只是一個標記做用。IBAction一樣是個標記關鍵字,它只能標記方法,它IB用IBAction標記的方法能夠被某個控件觸發。
經過編程的方式建立view,以下代碼:
上述代碼首先獲得屏幕的frame,而後根據frame生成了一個contentView,並指定當前ViewController的root view爲contentView,而後生成了一個LevelView的自定義View並將它經過addSubview:方法添加到當前ViewController當中,完成view的初始化加載。
關於loadView方法的重寫,官方文檔中有一個明顯的註釋,原文以下:
Note: When overriding the loadView
method to create your views programmatically, you should not call super
. Doing so initiates the default view-loading behavior and usually just wastes CPU cycles. Your own implementation of the loadView
method should do all the work that is needed to create a root view and subviews for your view controller.
意思是當經過代碼方式去建立你本身的view時,在loadView方法中不該該調用super,若是調用[super loadView]會影響CPU性能。
接下來咱們看看ViewController中的view是如何被卸載的:
從圖中能夠看到,當系統發出內存警告時,會調用didReceiveMemoeryWarning方法,若是當前有能釋放的view,系統會調用viewWillUnload方法來釋放view,完成後調用viewDidUnload方法,至此,view就被卸載了。此時原來指向view的變量要被置爲nil,具體操做是在viewDidUnload方法中調用self.myButton = nil;
小結一下:
loadView和viewDidLoad的區別就是,loadView時view尚未生成,viewDidLoad時,view已經生成了,loadView只會被調用一次,而viewDidLoad可能會被調用屢次(view可能會被屢次加載),當view被添加到其餘view中以前,會調用viewWillAppear,以後會調用viewDidAppear。當view從其餘view中移除以前,調用viewWillDisAppear,移除以後會調用viewDidDisappear。當view再也不使用時,受到內存警告時,ViewController會將view釋放並將其指向爲nil。
ViewController的生命週期中各方法執行流程以下:
init—>loadView—>viewDidLoad—>viewWillApper—>viewDidApper—>viewWillDisapper—>viewDidDisapper—>viewWillUnload->viewDidUnload—>dealloc