看了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代碼ViewController
git
首先必須說明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
- init
消息- initWithCoder:
消息- awakeFromNib
消息- awakeFromNib
消息- initWithCoder:
消息- awakeFromNib
消息可見自定義的Object的建立時間是早於VC的,至於爲何- awakeFromNib
收到的晚於VC,是由於建立出來的Object須要被VC強引用ide
建立出來的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由於沒有被強引用而隨後被釋放。
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從->這裏下載<-
模板類
,繼承+重載無可非議(但像UITableView這種被設計成配置類
的類,咱們更應該去配置它,而非繼承它,更別說NSArray,NSString這種類簇的工具類了)https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html
http://www.objc.io/issue-13/behaviors.html
原創文章,轉載請註明源地址,blog.sunnyxx.com