前言
之前在自己公司开发过程之中,一直就是想办法把代码写的漂亮,可复用度高,就是不断地稠代码,分模块.具体怎么做
写出比较完美的代码,自己也不知道,现在有时间整理一些自己学习的心得,废话不多说,先飞一波!
在开始之前还是想讲一下,代码的规范
- 先是life cycle,即controller的生命周期等一些方法如:
#pragma mark - lifecycle
- (void)viewDidLoad
- 然后是 private method,一些私有方法(虽然说好的代码,控制器里面没有私有方法,不过毕竟不是超级大神),即你自己封装的一些功能类方法
#pragma mark - private method
- (void)setupRefreshView
- 然后是Delegate方法实现,先系统代理,然后自己写的代理
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
#pragma mark - SegmentCellDelegate
- (void)segmentClickedWithIndex:(NSInteger)selectedIndex
- 然后是event response,所有button、gestureRecognizer的响应事件都放在这个区域里面,不要到处乱放。
#pragma mark - event response
//点击空白处释放键盘
- (void)tap
//点击退出按钮
-(void)existButton:(UIButton *)button
- 然后才是getters and setters,和 懒加载
#pragma mark - Getters and Setters
- (NSMutableArray *)searchSections {
if (!_searchSections) {
_searchSections = [[NSMutableArray alloc] init];
}
return _searchSections;
}
为什么要这样要求?
我见过无数ViewController,代码布局乱得一塌糊涂,这里一个delegate那里一个getter,然后ViewController的代码一般都死长死长的,看了就让人头疼。
定义好这个规范,就能使得ViewController条理清晰,业务方程序员很能够区分哪些放在ViewController里面比较合适,哪些不合适。另外,也可以提高代码的可维护性和可读性。
好了,希望以上可以帮到大家,这也是我看了一些文章整理出来常用 mark分类方法.下面开始主题了,一直听别人说关于胖瘦Model的事,也不是很了解,下面我们
来扒一下他们的老底.是不是有些期待呢....
一 丶关于胖Model和瘦Model
- 什么叫胖Model?
胖Model包含了部分弱业务逻辑。胖Model要达到的目的是:Controller从胖Model这里拿到数据之后,不用额外做操作或者只要做非常少的操作,就能够将数据直接应用在View上.
FatModel:
@property (nonatomic, copy) NSString *calId; //日程id
@property (nonatomic, copy) NSString *title; //日程标题
/*
* 判断自己是否是该日程参与者
*/
+ (BOOL)isCalendarActory:(NSString *)doneUsers;
Controller:
BOOL ret = [FatModel isCalendarActory:@“”];
其优点是:
这属于业务代码,算是弱业务。FatModel做了这些弱业务之后,Controller就能变得非常skinny,Controller只需要关注强业务代码就行了。众所周知,强业务变动的可能性要比弱业务大得多,弱业务相对稳定,所以弱业务塞进Model里面是没问题的。
另一方面,弱业务重复出现的频率要大于强业务,对复用性的要求更高,如果这部分业务写在Controller,类似的代码会洒得到处都是,一旦弱业务有修改(弱业务修改频率低不代表就没有修改),这个事情就是一个灾难。如果塞到Model里面去,改一处很多地方就能跟着改,就能避免这场灾难。
其缺点是:
胖Model相对比较难移植,虽然只是包含弱业务,但好歹也是业务,迁移的时候很容易拔出萝卜带出泥。另外一点,MVC的架构思想更加倾向于Model是一个Layer,而不是一个Object,不应该把一个Layer应该做的事情交给一个Object去做。最后一点,软件是会成长的,FatModel很有可能随着软件的成长越来越Fat,最终难以维护。
- 2.什么叫瘦Model?
瘦Model只负责业务数据的表达,所有业务无论强弱一律扔到Controller。ThinModel要达到的目的是,尽一切可能去编写细粒度Model,然后配套各种helper类或方法来对弱业务做抽象,强业务依旧交给Controller。举个例子:
ThinModel:
@property (nonatomic, copy) NSString *calId; //日程id
@property (nonatomic, copy) NSString *title; //日程标题
ThinHelper:
/*
* 判断自己是否是该日程参与者
*/
+ (BOOL)isCalendarActory:(NSString *)doneUsers;
Controller:
BOOL ret = [ThinHelper isCalendarActory:@“”];
其优点是:
由于ThinModel跟业务完全无关,它的数据可以交给任何一个能处理它数据的Helper或其他的对象,来完成业务。在代码迁移的时候独立性很强,很少会出现拔出萝卜带出泥的情况。另外,由于ThinModel只是数据表达,对它进行维护基本上是0成本,软件膨胀得再厉害,ThinModel也不会大到哪儿去。
其缺点是:
缺点就在于,Helper这种做法也不见得很好,这里有一篇文章批判了这个事情。另外,由于Model的操作会出现在各种地方,ThinModel在一定程度上违背了DRY(Don't Repeat Yourself)的思路,Controller仍然不可避免在一定程度上出现代码膨胀。
二丶MVC
M应该做的事:
- 给ViewController提供数据
- 给ViewController存储数据提供接口
- 提供经过抽象的业务基本组件,供Controller调度
C应该做的事:
- 管理View Container的生命周期
- 负责生成所有的View实例,并放入View Container
- 监听来自View与业务有关的事件,通过与Model的合作,来完成对应事件的业务。
V应该做的事:
- 响应与业务无关的事件,并因此引发动画效果,点击反馈(如果合适的话,尽量还是放在View去做)等。
- 界面元素表达
三丶MVCS
苹果自身就采用的是这种架构思路,从名字也能看出,也是基于MVC衍生出来的一套架构。从概念上来说,它拆分的部分是Model部分,拆出来一个Store。这个Store专门负责数据存取。但从实际操作的角度上讲,它拆开的是Controller。
这算是瘦Model的一种方案,瘦Model只是专门用于表达数据,然后存储、数据处理都交给外面的来做。MVCS使用的前提是,它假设了你是瘦Model,同时数据的存储和处理都在Controller去做。所以对应到MVCS,它在一开始就是拆分的Controller。因为Controller做了数据存储的事情,就会变得非常庞大,那么就把Controller专门负责存取数据的那部分抽离出来,交给另一个对象去做,这个对象就是Store。这么调整之后,整个结构也就变成了真正意义上的MVCS。
TCStore:
//主要为本地数据查询,删除,跟新 提供接口
- (NSMutableArray *)fetchLocalFavoritesWithType:(NSString *)type
Controller:
self.dataSource = [[TCStore sharedInstance] fetchLocalFavoritesWithType:@“”];
四丶MVVM
1.纯属打酱油
MVVM去年在业界讨论得非常多,无论国内还是国外都讨论得非常热烈,尤其是在ReactiveCocoa这个库成熟之后,ViewModel和View的信号机制在iOS下终于有了一个相对优雅的实现。MVVM本质上也是从MVC中派生出来的思想,MVVM着重想要解决的问题是尽可能地减少Controller的任务。
2.看着好看有分割线
不管MVVM也好,MVCS也好,他们的共识都是Controller会随着软件的成长,变很大很难维护很难测试。只不过两种架构思路的前提不同,MVCS是认为Controller做了一部分Model的事情,要把它拆出来变成Store,MVVM是认为Controller做了太多数据加工的事情,所以MVVM把数据加工的任务从Controller中解放了出来,使得Controller只需要专注于数据调配的工作,ViewModel则去负责数据加工并通过通知机制让View响应ViewModel的改变。
3.卧槽怎么还有
MVVM是基于胖Model的架构思路建立的,然后在胖Model中拆出两部分:Model和ViewModel。关于这个观点我要做一个额外解释:胖Model做的事情是先为Controller减负,然后由于Model变胖,再在此基础上拆出ViewModel,跟业界普遍认知的MVVM本质上是为Controller减负这个说法并不矛盾,因为胖Model做的事情也是为Controller减负。
另外,我前面说MVVM把数据加工的任务从Controller中解放出来,跟MVVM拆分的是胖Model也不矛盾。要做到解放Controller,首先你得有个胖Model,然后再把这个胖Model拆成Model和ViewModel。
4.马上完了
前面扯了那么多,其实归根结底就是一句话:在MVC的基础上,把C拆出一个ViewModel专门负责数据处理的事情,就是MVVM。然后,为了让View和ViewModel之间能够有比较松散的绑定关系,于是我们使用ReactiveCocoa,因为苹果本身并没有提供一个比较适合这种情况的绑定方法。iOS领域里KVO,Notification,block,delegate和target-action都可以用来做数据通信,从而来实现绑定,但都不如ReactiveCocoa提供的RACSignal来的优雅,如果不用ReactiveCocoa,绑定关系可能就做不到那么松散那么好,但并不影响它还是MVVM。
在实际iOS应用架构中,MVVM应该出现在了大部分创业公司或者老牌公司新App的iOS应用架构图中,据我所知易宝支付旗下的某个iOS应用就整体采用了MVVM架构,他们抽出了一个Action层来装各种ViewModel,也是属于相对合理的结构。
所以Controller在MVVM中,一方面负责View和ViewModel之间的绑定,另一方面也负责常规的UI逻辑处理。
viewCell
@property (nonatomic, strong) viewModel *model;
Model
@property (nonatomic, copy) NSString *title; //标题
viewModel
@property (nonatomic, strong) Model *model;
/**
* 头像frame
*/
@property (nonatomic, assign, readonly) CGRect headerFrame;
+(void)caluCellHightWith:(RHFlowCategoryCellType)type;
Controller
viewCell.model = self.dataSource[index.row];
五丶VIPER
VIPER(View,Interactor,Presenter,Entity,Routing)。VIPER我并没有实际使用过,我是在objc.io上第13期看到的。
但凡出现一个新架构或者我之前并不熟悉的新架构,有一点我能够非常肯定,这货一定又是把MVC的哪个部分给拆开了(坏笑)。事实情况是VIPER确实拆了很多很多,除了View没拆,其它的都拆了。
这个我就不讲了,不怎么用,如果有想了解的,请去网站了解.
参考资料:
http://casatwy.com/iosying-yong-jia-gou-tan-viewceng-de-zu-zhi-he-diao-yong-fang-an.html
(objc.io)
https://www.objc.io/issues/13-architecture/viper/