浅谈MVCS框架,基于YTKnetwork

2,345 阅读4分钟

前言

本文主要是针对目前我们项目中使用的框架进行一个讲解,使用的框架是MVCS,网络请求用的是YTKNetwork,欢迎各位大佬在下方进行留言,因为现在项目可能要重构,我就是个小白,也没有具体的优化方案。

原理

MVC就不过多的讲解了,我们只是在这个基础上添加了Service层,用来处理网路请求,以及回调的处理,参照的博客地址:

www.jianshu.com/p/8b0d06bd5… blog.csdn.net/wangyanchan…

代码

我自己写了一demo,基本跟目前项目架构类似,目前遇到的问题就是controller里边好多回调方法以及初始化方法,模块之间耦合性太高了,就比如跳转登录页面,然后从登录页面返回的时候需要判断好多条件,每个条件执行的回调方法可能还不一致,不方便维护。demo效果图如下:

M层

@interface HomeModel : ResponseModel
@property (nonatomic, copy) NSString    *iconImg;
@property (nonatomic, copy) NSString    *iconName;
@property (nonatomic, copy) NSString    *iconDesc;
@property (nonatomic, assign) int     type;
@end

其中ResponseModel 是继承自JSONModel的

Service层

主要是用来处理请求的,因为YTKNetwork的核心思想是把每一个请求都封装成一个类,然后通过service或者controller层进行调用

下边列一下每个类的作用,以及包括的方法:

Protocol 用来初始化数据的方法,因为可能多个页面需要用到,所以写成协议

@protocol HomeDataProtocol <NSObject>

- (void)initWithData:(id)data;

- (void)initWithData:(id)data selectIndex:(NSIndexPath *)indexPath;

@end

这是点击cell对应的加和减的代理方法

@protocol HomeTableViewCellDelegate <NSObject>

- (void)didClickPlusView:(UIButton *)plusView index:(NSInteger)index;
- (void)didClickMinusView:(UIButton *)minusView index:(NSInteger)index;

@end

RequestService 这个主要负责调用Request方法,里边可能会包含到首页模块中用到的方法

@implementation HomeRequestService

+ (void)requestWithUserId:(NSString *)userId
                 complete:(void(^)(id result,NSError *error))complete{
    HomeRequest *request    = [[HomeRequest alloc] init];
    request.userId  = userId;
    [request requestComplete:^(BaseRequest * _Nonnull request) {
        /// 这里边可以直接处理request返回的结果,但是不应该去处理,因为解析的工作完全可以统一处理
        [request handleRequestWithClass:NSArray.class
                           withComplete:^(id  _Nonnull model, NSError * _Nonnull error) {
            if (complete) {
                model   = [HomeModel arrayOfModelsFromDictionaries:model error:&error];
                complete(model,error);
            }
        }];
    }];
}

@end

Request 这个继承自YTKNetwork的请求,.m文件需要实现请求的二级路径、是否添加缓存、请求参数等等

@implementation HomeRequest

- (BOOL)enableMockData{
    /// 这是我们在猿题库的基础上自己定义了一个方法,是否加载本地的缓存
    ///  YES代表使用本地缓存,他会从本地查找HomeRequest.json文件进行解析,主要是为了测试数据源的修改
    return YES;
}

- (NSString *)requestUrl{
    /// 这是请求的二级路径,一级路径需要在程序启动进行配置
    return @"XXXXX/XXXX/AA.do";
}

- (YTKRequestMethod)requestMethod{
    /// 这是请求的方式
    return YTKRequestMethodPOST;
}

- (id)requestArgument{
    /// 这是请求的参数
    return @{@"userId":_userId};
}

@end

Controller层

主要负责页面UI的展示,以及请求数据,包括代理方法的实现,由于代码量多,只列出部分代码

@interface HomeViewController ()
<
UITableViewDelegate,
UITableViewDataSource,
HomeTableViewCellDelegate
>

@property (nonatomic, strong) UITableView   *tableView;
@property (nonatomic, strong) NSMutableArray    *dataArray;

@end

- (void)requestData{
    __weak typeof(self)weakSelf = self;
    [HomeRequestService requestWithUserId:@"test"
                                 complete:^(id  _Nonnull result, NSError * _Nonnull error) {
        if (!error) {
            /// 初始化数据
            [weakSelf.dataArray removeAllObjects];
            [weakSelf.dataArray addObjectsFromArray:result];
            [weakSelf.tableView reloadData];
            
        }else{
            /// 处理弹框或者什么的异常处理
            
        }
    }];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    HomeTableViewCell   *cell   = [tableView dequeueReusableCellWithIdentifier:identifier];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    cell.delegate   = self;
    [cell initWithData:self.dataArray[indexPath.row]
           selectIndex:indexPath];
    return cell;
}
/// 点击加的回调
- (void)didClickPlusView:(UIButton *)plusView index:(NSInteger)index{
    HomeModel   *model  = self.dataArray[index];
    model.type++;
    [self.tableView reloadRow:index
                    inSection:0
             withRowAnimation:UITableViewRowAnimationNone];
}

- (UITableView *)tableView{
    if (!_tableView) {
        _tableView  = [[UITableView alloc] initWithFrame:CGRectZero
                                                   style:UITableViewStylePlain];
        _tableView.delegate     = self;
        _tableView.dataSource   = self;
        _tableView.backgroundColor  = [UIColor redColor];
        [_tableView registerClass:[HomeTableViewCell class] forCellReuseIdentifier:identifier];
    }
    return _tableView;
}

View层就不过的叙述,就是UITableViewCell的创建

基类

BaseViewContoller 和ResponseModel 就不多数了,主要说下BaseRequest类,里边一共3个方法,是否加载本地缓存、发起请求、解析返回json

@interface BaseRequest : YTKRequest

/// 这个方法是否使用本地缓存,true代表使用
- (BOOL)enableMockData;

/// 最底层发起请求的方法              (所有请求都需要走这个方法)
/// @param complete 返回结果
- (void)requestComplete:(void(^)(BaseRequest *request))complete;

/// 最底层处理返回结果的方法        (所有返回结果都会走这个方法)
/// @param clsName 需要处理的类
/// @param complete 返回结果
- (void)handleRequestWithClass:(id)clsName withComplete:(void(^)(id model,NSError *error))complete;

@end

至于实现的话就是调用YTKNetwork的方法和调用jsonModel的一个解析方法就不在过多叙述

总结

优点

1,项目架构还是比较清晰的,而且也很好理解,上手容易。

2,减少了好多判断,比如请求参数的判断,这个交给了YTKNetwork,返回数据解析的判断,这个交给了JSONModel,而且还可以针对某个请求单独添加缓存。

3,可以单独配置某个请求是否用本地json,在接口还未实现的时候可以提取开发,只要有结构即可。

缺点

1,如果页面UI复杂,事件交互也比较多,那么Controller层代码量会暴增加,大部分都是delegate方法和getter方法,目前正在考虑如何剥离。

2,项目类会比较多,因为每个请求都是一个单独的类,目前项目大概100个接口左右,光请求的类就100+还不算service层,这个随着项目变大不知道是否会有影响。

3,模块和模块之间的耦合度还是很高,目前的架构还不适合模块的解耦。