iOS UIviewContoller瘦身大运动

  • 前言

通常一个项目中ViewController的代码最多,复用度最低,随着项目功能完善,一个臃肿的ViewContoller便出现了,如果这个时候来了新人接手项目!!!而你就是这个新人的话。Oh my god!看着可能多达上千行的代码,相信我,你会有一种蛋蛋的忧伤。感觉无从下手...一种无力感油然而生,感觉身体被掏空=。=

被掏空

来来来小伙子,喝一瓶


好的你明天可以不用来上班了
  • 本例实现一个从网络下载数据,显示到tableView中的demo最终只需要在viewController中写下代码便可实现(可能不是最优的,如果您有更好的建议,欢迎讨论,纠正我。):

 self.dataSouce = [PQTBDataSource dataSourceWith:_dataArray identifier:CELLIDENTIFIER cellConfigBlock:^(TableViewCell * _Nullable cell, id  _Nullable item) {
        [cell configCellWithIem:item];
    }];
    self.myTableView.dataSource = self.dataSouce;
    [self.myTableView registerNib:[UINib nibWithNibName:@"TableViewCell" bundle:nil] forCellReuseIdentifier:CELLIDENTIFIER];
    
    typeof(self) weakSelf = self;
    [NetWorkManager dataTaskWith:URL completionHandler:^(NSArray *itemsArray) {
        [weakSelf.dataSouce pq_updateWithArray:itemsArray];
        [weakSelf.myTableView reloadData];
    }];
  • 1 优化TableView的Datasource

. 先看优化前和优化之后的对比:
优化前

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _array.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
    }
    cell.textLabel.text = _array[indexPath.row];
    return cell;
}

优化后,且可复用

self.dataSouce = [PQTBDataSource dataSourceWith:_dataArray identifier:CELLIDENTIFIER cellConfigBlock:^(TableViewCell * _Nullable cell, id  _Nullable item) {
        //这里更新设置你的cell
    }];
    self.myTableView.dataSource = self.dataSouce;
  • 开始之前还扯一扯:在项目中如果你用到了两个以上的tableView的时候你会发现你一定会存在重复的代码,而且还是没啥意义的。比如
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _array.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
    }
    cell.textLabel.text = _array[indexPath.row];
    
    return cell;
}

先不用看里面写了啥!!!,基本雷同是不是?
你的tableview还会有

这里仅仅是开个玩笑哈 会报错的。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return [@"fuck" integerValue];
}

对于上面的代码,完全可以提取出来,让你的ViewController看起来舒服点。
让他减减肥...

开始干活了

.

  • 1 第一步,建一个类,并且实现datasource的方法。


    建一个类,名字你随意,我干了
  • 2 第二步,继承<UITableViewDataSource>
    既然把刚才上面列举的方法提取出来,这里肯定是我们自己去实现了。
    先实现方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 在某组里面有多少个cell
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
   每个cell的样式 还要从复用池取出cell需要Identifier
}

然后你就发现这里我们需要一个数组,所以这里需要

  • 一个数组

  • 一个identifier

在考虑一下有必要公开么?笔者认为是没有必要公开的,所以就写在.m文件中

//传入之后不允许用户在外面随意更改数据
@property (nonatomic,strong,readwrite) NSMutableArray * _Nullable valuesArray;
@property (nonatomic,copy) NSString * identifier;

上面的代码中你会发现有一个readwrite,这个是干啥的呢?主要是配合.h文件中的

@interface PQTBDataSource : NSObject <UITableViewDataSource>
//传入之后不允许用户在外面随意更改数据
@property (nonatomic,strong,readonly) NSMutableArray * _Nullable valuesArray;

如果你还是不知道啥意思?看图
![现在你只能读,不能写。但是又想在.m中使用self.valuesArray的话可以这样写](http://upload-images.jianshu.io/upload_images/1940927-db83b6518a22f1a6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
到目前为止,我们已经确定了两个东西,一个是数组,一个是Identifier。
还有一个问题:
##### 这个时候每一个的cell要怎么设置,内部不知道,cell可以是很多种,自定义的xib画的,类名都不一样,里面完成不了对cell的设置。所以我们需要我们得交给外面去处理,这里你想使用delegate或者block随便你,不过笔者比较喜欢block,代码内聚。

到目前为止,我们需要的东西就知道了:
- 数组
- identifier
- 一个block
于是就可以写一个类似于:

  • (nonnull instancetype)dataSourceWith:(nullable NSArray *)values identifier:(nullable NSString *)identifier cellConfigBlock:(nullable void(^)( id _Nullable cell,id _Nullable item))block;
  • (nonnull instancetype)initWithDataSource:(nullable NSArray *)values identifier:(nullable NSString *)identifier cellConfigBlock:(nullable void(^)(id _Nullable cell,id _Nullable item))block;
的方法。
到这里datasource基本上就设置好了,把方法都实现一下
  • (nonnull instancetype)dataSourceWith:(nullable NSArray *)values identifier:(nullable NSString *)identifier cellConfigBlock:(nullable void(^)( id _Nullable cell,id _Nullable item))block{
    return [[self alloc]initWithDataSource:values identifier:identifier cellConfigBlock:block];
    }
  • (nonnull instancetype)initWithDataSource:(nullable NSArray *)values identifier:(nullable NSString *)identifier cellConfigBlock:(nullable void(^)(id _Nullable cell,id _Nullable item))block
    {
    self = [super init];
    if (self) {
    self.identifier = identifier ;
    self.valuesArray = [NSMutableArray arrayWithArray:values];
    self.cellConfigBlock = [block copy];
    }
    return self;
    }

  • (id _Nullable )itemWithIndexPath:(NSIndexPath *)indexPath{
    return self.valuesArray[indexPath.row];
    }

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.valuesArray.count;
    }

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    id cell = [tableView dequeueReusableCellWithIdentifier:self.identifier forIndexPath:indexPath];
    id item = [self itemWithIndexPath:indexPath];
    self.cellConfigBlock(cell,item);
    return cell;
    }

于是你ViewController中的tableView就可以这样子设置:

self.dataSouce = [PQTBDataSource dataSourceWith:_dataArray identifier:CELLIDENTIFIER cellConfigBlock:^(TableViewCell * _Nullable cell, id _Nullable item) {
//这里更新设置你的cell
}];
self.myTableView.dataSource = self.dataSouce;

这样子你的ViewController就几行代码就实现了之前数十行要实现且没有啥子意义的代码,并且你还可以在其他的tableView中去使用。


 > - ### 2 封装一下数据请求,这部分的代码没有viewController没有必要去管理,他只需要一个结果就好了,

既然只需要一个结果,那么我们最终就放回一个结果(不管请求失败还是成功都只是一个结果)。但是我们并不知道什么时候会请求完成或者失败,不能一直等待,所以一定是异步进行请求,请求完成就通过block回调。
- 2.1 分析一下需要什么才可以请求一个数据
 -URL
这里我们不考虑太复杂的情况了,随便请求一点数据好了。
所以可以封装一个方法大致如下:

  • (void)dataTaskWith:(NSString *)url completionHandler:(void(^)(NSArray * itemsArray))block;
这里可能你会注意到,为什么我返回的是一个数组:是这样子的,viewController同样不需要知道我们数据转化为模型的过程,一样的理念,他只需要结果,一个有用的结果就行了。
实现代码
  • (void)dataTaskWith:(NSString *)url completionHandler:(void(^)(NSArray * itemsArray))block{
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

    NSURL *URL = [NSURL URLWithString:url];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];

    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
    NSDictionary * dict = (NSDictionary *)responseObject;
    NSMutableArray * array = [NSMutableArray array];
    NSArray * objects = dict[@"subjects"];
    for (NSDictionary * dict in objects) {
    [array addObject:[TableViewModel tableViewModelWith:dict]];
    }
    if (block) {
    block(array);
    }
    }];
    [dataTask resume];
    }


在这里我们同时还生成了一个Model,最后我们只需要把模型返回就好。
模型
  • (instancetype)tableViewModelWith:(NSDictionary *)dict;
实现
  • (instancetype)tableViewModelWith:(NSDictionary *)dict{
    TableViewModel * model = [[self alloc]init];
    [model setValuesForKeysWithDictionary:dict];
    return model;
    }
  • (void)setValue:(id)value forUndefinedKey:(NSString *)key{

    if ([key isEqualToString:@"id"] == YES) {
    _ID = value;
    }
    }

  • (void)setImages:(NSDictionary *)images{
    _images = images[@"small"];
    }

到这里,我们基本上就已经实现了代码啦!!!!
于是乎,我们在viewController中还要写上:

typeof(self) weakSelf = self;
[NetWorkManager dataTaskWith:URL completionHandler:^(NSArray *itemsArray) {
[weakSelf.dataSouce pq_updateWithArray:itemsArray];
[weakSelf.myTableView reloadData];
}];

当我们的数据请求回来刷新tableView一次。

> - #### 3.最后一点,很多时候我们需要实现右滑功能,这里实现了一下,右滑删除功能,同样不用再viewController中去写代码,代码量没有增加,功能却实现了,而且这样子做的好处就是除了了问题就可以知道是datasource不用再viewController中苦苦寻找。

  • (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
    return YES;
    }
  • (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    [self.valuesArray removeObjectAtIndex:indexPath.row];
    [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }
The end
demo <https://github.com/codepgq/PQSeparationCode>
码字不易,看完如果对你有帮助,赞一个就是对笔者莫大的鼓励.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容