iOS多种类型的cell处理方案

在项目开发中UITableView和UICollectionView应该是最长用的控件了吧,而这两种控件的核心是cell的处理和展示。随着App的发展和需求的不断累加,页面是单一cell的情况越来越少,更多的是各种复杂cell的组合。常见的比如App的首页


app首页示例图

那么像这种页面我们是如何处理cell的呢?

1.最常见的也是很多人会不经思考的,直接根据indexPath一一对应,写出下面的代码:

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{

    if(indexPath.section==0) {

    }

}

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath{

    [tableViewdeselectRowAtIndexPath:indexPath animated:YES];

    if(indexPath.section==0) {

   }
}

虽然这种在开发阶段很容易,但是在后期的二次开发和维护上改一个地方tableview的delegate和datasource的方法都需要改,成本很高。而且cellForRowAtIndexPath的方法里面是清一色的if-else,然后是做了各种各样的事情,很容易造成代码的臃肿,动不动就是几十行或者几百行代码,不利于阅读和重用。

这种方案的缺点有以下几点:

1.一般情况下项目中不建议出现0、1等具体的数字,因为它除了表示位置之外,毫无其他意义。

2.容易出错,在cell代理方法,高度代理方法,点击代理方法里面要保持一致,容易出错。

3.不方便修改,如果要修改两个cell的顺序或者添加修改,要修改好几个地方,改动太大。

2.根据model来对应cell,cell面向model开发

前面提到了不因该出现indexPath等具体的位置数字,对于一个tableview,位置数字肯定是有的,我们要消除数字,那就得找到相应的数据来代替它。这里,主要的场景一般都是一个类型的数据(model)对应一种类型的cell,所以类型是固定的,所以我们用一个枚举来定义所有类型的cell

typedefNS_ENUM(NSInteger, HomeCellType) {

 HomeCellTypeOne =0,

 HomeCellTypeTwo 

 HomeCellTypeThree, 

 HomeCellTypeFourl, 

 };

然后在cellForRow方法,根据model类型加载对应的cell,例如:

   id model = self.viewModel.dataArray[indexPath.row];

switch([self getHomeCellType] ){

  caseHomeCellTypeOne:

 HomeCellOne *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[HomeCellOne cellIdentifier] forIndexPath:indexPath];

   breke;

caseHomeCellTypeOne:

 HomeCellTwo *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[HomeCellTwo cellIdentifier] forIndexPath:indexPath];

   breke;

   ....

}

 - (HomeCellType)getHomeCellType:(id)model {

        HomeCellType type = HomeCellTypeOne;

        if([model isKindOfClass:[HomeCellTypeOneModel class]]) {

            type = HomeCellTypeOne;

        }else if([model isKindOfClass:[HomeCellTypeTwoModel class]]) {

            type = HomeCellTypeTwo;

        }else if(){

        }

      ...

}

这样看到了cellType或者model就知道如何去处理相应的cell了,清晰易理解。而且如果想复用、删除、添加、改动顺序,只需要改动数据源即可,其他不需要动,改动量很小。但是这样写的还不是很好,cell和datasource的cellForRowAtIndexPath耦合的还有点严重。那如果其他的地方只是用到了部分cell类型,我们还需要把上面的代码再copy一份?或者说我想让cell根据model去自动选择cell类型,而不是import各种cell。头文件,在cellForRowAtIndexPath方法里面判断,不依赖具体的cell呢?

那么我的面向协议开发的设计模式就上场了。就是让model继承一个协议,该协议实现了cell的一些方法,例如cell的复用标示、cell的类型、cell的高度、cell的点击事件等。

改进版

1.定义协议接口

@protocol ModelConfigProtocol

@optional

/**

获取 cell 的复用标识

@return 复用标识

*/

- (nullableNSString*)cellReuseIdentifier;

/**

获取 cell 的类型

@return cell 的类型

*/

- (cellType)cellType;

/**

获取 cell 的高度

@param indexPath indexPath

@return 高度

*/

- (CGFloat)cellHeightWithindexPath:(NSIndexPath*)indexPath;

/**

cell 点击

@param indexPath indexPath

@param other 其它对象

*/

- (void)cellDidSelectRowAtIndexPath:(NSIndexPath*)indexPath other:(_Nullable id)other;

2.然后实现实现该协议接口。定义一个抽象类的model遵守该协议实现协议

@interface BaseModel : NSObject<ModelConfigProtocol>

@end

@implementation BaseModel

- (cellType)cellType{

    return0;

}

- (NSString*)cellReuseIdentifier{

    return@"";

}

- (CGFloat)cellHeightWithindexPath:(NSIndexPath*)indexPath{

    return0.0;

}

- (void)cellDidSelectRowAtIndexPath:(NSIndexPath*)indexPath other:(_Nullable id)other{

    return;

}

@end

3.具体的model继承自BaseModel,然后子类model具体实现ModelConfigProtocol的协议方法

4.定义的一个抽象类的cell,开放赋值的接口

@interfaceBaseCell : UITableViewCell

@property (nonatomic,strong) id<ModelConfigProtocol> model;

@end

@implementation BaseCell

- (void)setModel:(id)model{

}

@end

5.具体的cell继承自BaseCell,然后子类cell具体实现setModel方法

6.TableView代理里数据返回

#pragma mark ---- UITableViewDelegate ----

- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath

{

id<ModelConfigProtocol> model =self.listArray[indexPath.row];

return [model cellHeightWithindexPath:indexPath];

}

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath

{

[tableView deselectRowAtIndexPath:indexPath animated:YES];

id<ModelConfigProtocol> mdoel =self.viewModel.dataArray[indexPath.row];

[model cellDidSelectRowAtIndexPath:indexPath other:nil];

}

#pragma mark ---- UITableViewDataSource ----

- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView;

{

return1;

}

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{

return self.viewModel.dataArray.count;

}

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath;

{

id<ModelConfigProtocol> model =self.viewModel.dataArray[indexPath.row];

    BaseCell *cell = [tableView dequeueReusableCellWithIdentifier:[model cellReuseIdentifier]];

    cell.cellConfig = model;

returncell;

}

一般的一种类型的cell对应一种model,如果你想一种model对应多种cell,例如微信消息,有文本消息、图片消息、语音消息、红包消息、视频消息等。你可以在具体model的cellType再做一层判断。最厉害的地方在于可以和MVVM、适配器无缝对接,写一个BaseViewController实现这些,然后其他ViewController继承它,只需改变数据源,即可实现用最少的代码实现复杂的页面展示。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容