这几天思考项目重构的问题,我就啰嗦两句。项目重构说白了就是为controller减负,解耦合。之前项目都是使用mvc模式写的,发现这样写有个弊端,就是一堆代码逻辑都堆积在controller里面,导致有些类文件庞大,有的多达上千行的代码量,阅读起来十分困难,更别说重用了,改个bug都困难。
大家有兴趣的话可以阅读下唐巧的被误解的 MVC 和被神化的 MVVM
站在大牛的肩膀上学习,总是事半功倍的。下面我们来说下MVP架构,插一句,没有任何架构设计是完美的,我们只能给不同的需求制定不同的架构设计,去降低耦合,提高复用。这是MVPDemo,需要的话自行下载。
这是MVP架构设计图,第一次画,有些粗糙
下面是具体的代码实现:
先来看下类结构
首先来定义一个view的协议,用来处理数据回调,上代码:
#import <Foundation/Foundation.h>
@protocol BaseViewProtocol <NSObject>
- (void)showRemindTitle:(NSString *)message;
@optional
- (void)testTouchAction:(NSInteger)index;
@end
接下来在TabViewController里面去写需求,让P 层执行
@interface TableViewController ()<BaseViewProtocol>
//V 层包括UIView 和UIViewController及子类,需要持有P 层的实例对象
@property (nonatomic, strong) HomePresenter *presenter;
@end
@implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化一个P对象
_presenter = [[HomePresenter alloc] init];
//使用协议绑定进行数据传输
_presenter.protocol = self;
//显示head view,这里在P层创建了headView,当然也可以在Controller里面创建,传入P层
self.tableView.tableHeaderView = _presenter.headView;
[_presenter loadData];
}
- (void)showRemindTitle:(NSString *)message{
if (message) {
//show view
[[[UIAlertView alloc] initWithTitle:@"温馨提示" message:message delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil] show];
}
}
MVP中主要代码集中在P层,下面是P层代码逻辑:
@interface HomePresenter ()<BLoopImageViewDelegate>
@end
/**
* P 层作为协调者(中介),需要持有M 层和V 层的对象的引用
* 适当的时候去协调他们的更新逻辑
*/
@implementation HomePresenter
- (BLoopImageView *)headView{
if (!_headView) {
_headView = [[BLoopImageView alloc] initWithFrame:CGRectMake(0, 0, Screen_bounds.size.width, 240) delegate:self imageItems:nil isAuto:YES];
}
return _headView;
}
- (void)setProtocol:(id<BaseViewProtocol>)protocol{
_protocol = protocol;
}
- (void)loadData{
[HomeListModel startGETURL:^(NSArray *info, NSString *error) {
if (error) {
//当请求出错时需要回调给出提示信息
if (self.protocol) {
[self.protocol showRemindTitle:error];
}
} else {
[self.headView setItemsArr:info];
}
}];
}
#pragma mark
- (void)foucusImageFrame:(BLoopImageView *)imageView didSelectItem:(BLoopImageItem *)item{
NSLog(@"item.title = %@",item.title);
[self.protocol testTouchAction:item.tag];
}
- (void)foucusImageFrame:(BLoopImageView *)imageView currentItem:(NSInteger)index{
NSLog(@"index = %zd",index);
}
- (void)cancelHeadView{
self.headView = nil;
}
M层代码就变得很清爽了,只专一的去做数据处理,并组织好UI 显示的数据,看代码:
@implementation HomeListModel
+ (void)startGETURL:(void (^)(NSArray *info, NSString *error))block{
[[BKNetworking share] get:@"http://bapi.baby-kingdom.com/index.php?mod=stand&op=index&ver=3.6.0&app=ios" completion:^(BKNetworkModel *model, NSString *netErr) {
if (netErr) {
block(nil, netErr);
} else {
if (model.status) {
NSDictionary *data = model.data;
if ([data isKindOfClass:[NSDictionary class]]) {
NSArray *items = [self loadPackageData:data[@"lists"]];
//创建model
block ( items, nil );
}
}
}
}];
}
//组装数据并返回
+ (NSArray *)loadPackageData:(NSArray *)images{
//添加最后一张图 用于循环
int length = (unsigned)images.count;
NSMutableArray *itemArray = [NSMutableArray arrayWithCapacity:length+2];
if (length > 1)
{
NSDictionary *dict = images[length-1];
BLoopImageItem *item = [[BLoopImageItem alloc] initWithDict:dict tag:-1];
[itemArray addObject:item];
}
for (int i = 0; i < length; i++)
{
NSDictionary *dict = images[i];
BLoopImageItem *item = [[BLoopImageItem alloc] initWithDict:dict tag:i];
[itemArray addObject:item];
}
//添加第一张图 用于循环
if (length >1)
{
NSDictionary *dict = images[0];
BLoopImageItem *item = [[BLoopImageItem alloc] initWithDict:dict tag:length];
[itemArray addObject:item];
}
return itemArray;
}
@end
参考文章:
iOS 软件架构 - MVC, MVP, MVVM 和 VIPER 「译」