0代碼ViewController

本文原文發表自個人【自建博客】(http://blog.sunnyxx.com/2014/07/17/ios_0code_vc/),cnblogs同步發表,格式未經調整,內容以原博客爲準

 

我是前言

看了objc.io中的《Behaviors in iOS Apps》(objccn上也有中文翻譯版)後,終於如夢初醒了IB中的這個低調的Object存在的意義:html

再加上一樣被輕視的Runtime Attributes:ios

有了這些,IB纔算完整和強大。
最近看了一些文章,加上工程中也遇到的坑,矛頭都指向了MVC(Massive View Controller):臃腫的ViewController所引起的不爽,objc.io也是以一個《Lighter View Controllers》開篇。從把DataSource和Delegte從VC中分離,到把Model邏輯整個分離的MVVM,VC一步步瘦身,再到這篇Behavior模式巧妙的組件式的分離了功能。但有沒有想過,爲啥往一個頁面寫點啥東西就必定要子類化一個VC呢,使用上面兩個IB的功能,咱們能夠激進地實驗一次0代碼ViewControllergit


Top Level Objects

首先必須說明Top Level Objects這個概念,根據apple文檔:github

The top-level objects are the subset of these objects that do not have a parent object. The top-level objects typically include only the windows, menubars, and custom controller objects that you add to the nib file. (Objects such as File’s Owner, First Responder, and Application are placeholder objects and not considered top-level objects.)windows

因此,IB裏面的Object控件其實就是向Controller中添加Custom Top Level Object,在storyboard中被擺在下面的位置:數組

事實上任何Object均可以添加,這裏出現了一個LoginViewModel對象、一個菊花、一個Tap手勢。app

Nib對象的建立順序

  1. 自定義的Top Level Objects收到- init消息
  2. ViewController收到- initWithCoder:消息
  3. 自定義的Top Level Objects 收到- awakeFromNib消息
  4. ViewController收到- awakeFromNib消息
  5. 子View分別收到- initWithCoder:消息
  6. 子View分別收到- awakeFromNib消息

可見自定義的Object的建立時間是早於VC的,至於爲何- awakeFromNib收到的晚於VC,是由於建立出來的Object須要被VC強引用ide

VC對自定義Objects的強引用

建立出來的Object必須保證不被釋放,這個強引用由VC實現,雖然說沒有顯示的API,但從UIViewController.h中能夠看到馬腳:工具

1
2
3
4
5
6
7
@interface UIViewController : UIResponder {
    @package
    // ...
    NSDictionary  *_externalObjectsTableForViewLoading;
    NSArray       *_topLevelObjectsToKeepAliveFromStoryboard;
    // ... } 

經過KVC能夠很輕鬆的取出來:佈局

1
2
NSArray *objs = [vc valueForKey:@"_topLevelObjectsToKeepAliveFromStoryboard"]; NSDictionary *dict = [vc valueForKey:@"_externalObjectsTableForViewLoading"]; 

這些objects就是被這個數組強引用的,感興趣的能夠打印下看看結果。
注:只在storyboard下生效,在xib下,被建立的Object由於沒有被強引用而隨後被釋放。


構建0代碼VC的簡單登陸場景

storyboard中拉出個VC,隨便擺擺:

建立一個ViewModel類(也就是Behavior類),裏面寫須要的IBOutlet和IBAction

1
2
3
4
5
6
7
@interface XXLoginViewModel : NSObject @property (nonatomic, weak) IBOutlet UIViewController *ownerViewController; @property (nonatomic, weak) IBOutlet UITextField *usernameTextField; @property (nonatomic, weak) IBOutlet UITextField *passwordTextField; @property (nonatomic, weak) IBOutlet UIActivityIndicatorView *spinner; - (IBAction)loginAction:(id)sender; @end 

storyboard中拖出來一個Object到左邊,設置類爲這個XXLoginViewModel, 將全部IBOutlet和IBAction鏈接好

這樣,就能夠在自定義Object中隨心所欲了,須要什麼就從storyboard裏面Outlet出來就行了,好比點擊以後的跳轉:

1
2
3
4
- (IBAction)loginAction:(id)sender { [self.ownerViewController performSegueWithIdentifier:@"LoginSegue" sender:nil]; } 

具體的代碼不show了,Demo的效果以下:

固然,TableView的delegate和data source也都是能夠託管到自定義Object中,同時,Object之間也能夠有Outlet關係哦,剩下的就純靠想象力了。

這個簡單的demo從->這裏下載<-


What’s more

  • 首先,此次實驗並不是代表咱們應該寫0代碼的VC,UIViewController自己被設計做爲一個模板類,繼承+重載無可非議(但像UITableView這種被設計成配置類的類,咱們更應該去配置它,而非繼承它,更別說NSArray,NSString這種類簇的工具類了)
  • 組合模式以十分靈活的方式劃分功能,Demo中只用了一個ViewModel,其實徹底能夠組合一個Animation類實現動畫,組合一個HTTP類來發請求?,組合一個處理旋轉屏幕的類等等,並且完成這些子功能的代碼集中在一個類中,而不是分散在VC的各個角落,兩個功能的小模塊間能夠說沒有耦合
  • VC沒有代碼,但storyboard已經幹了VC該乾的事,如建立和佈局子View、設置Autolayout、設置action,定義跳轉等。我想,Apple祭出storyboard的目的就在於將純視圖和純代碼邏輯分離,VC本該Control它的View,而不是本身就是那個View

References

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html
http://www.objc.io/issue-13/behaviors.html


原創文章,轉載請註明源地址,blog.sunnyxx.com

相關文章
相關標籤/搜索