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

相关文章
相关标签/搜索