iOS封装、继承、多态项目应用-tableview(OC篇)

概念

封装:提供可以调用的接口,隐藏具体实现方案
继承:子类拥有父类的成员变量和方法,可以较大程度减少代码的重复率
多态:父类指针指向子类对象(实例对象调用的方法会寻找到真实的类进行调用)

应用

封装一个常用的UITableView为例子

  • 普通的tableView复用代码
    WCBaseTableViewCell
@implementation WCBaseTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self prepareUI];
    }
    return self;
}

- (void)prepareUI {
    self.backgroundColor = [UIColor colorWithRed:random() % 255 / 255.0  green:random() % 255 / 255.0 blue:random() % 255 / 255.0 alpha:1.0];
}

@end

ViewController

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *ID = @"WCBaseTableViewCell";
    WCBaseTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[WCBaseTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return cell;
}

效果

*效果*


  • UITableViewCell的初步封装
    从上面的tableViewCell创建的过程来看(如下)
static NSString *ID = @"WCBaseTableViewCell";
    WCBaseTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[WCBaseTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return cell;

既然每次实例化一个cell对象都需要写这么一大段代码,那么是否可以把这些代码复用起来(如果WCBaseTableViewCell在多个控制器中使用到,那么就会使得控制器会有很多重复的代码),于是,我们想到了类方法来进行对象的实例化,方法如下:
WCBaseTableViewCell.h

@interface WCBaseTableViewCell : UITableViewCell

+ (instancetype)wc_baseTableViewCellWithTableView:(UITableView *)tableView;

@end

WCBaseTableViewCell.m

@implementation WCBaseTableViewCell

+ (instancetype)wc_baseTableViewCellWithTableView:(UITableView *)tableView {
    static NSString *ID = @"WCBaseTableViewCell";
    WCBaseTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[WCBaseTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return cell;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self prepareUI];
    }
    return self;
}

- (void)prepareUI {
    self.backgroundColor = [UIColor colorWithRed:random() % 255 / 255.0  green:random() % 255 / 255.0 blue:random() % 255 / 255.0 alpha:1.0];
}

@end
  • ViewController中的使用*
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    WCBaseTableViewCell *cell = [WCBaseTableViewCell wc_baseTableViewCellWithTableView:tableView];
    return cell;
}

总结
以上的普通的tableView复用代码UITableViewCell的初步封装结果是一致的,使用了工厂方法,将一部分在控制器中常使用的代码放到了cell里面,使得控制器的代码更加易读和简洁,而WCBaseTableViewCell类中的这一部分代码,提供了接口供外部使用声明变量,这,就是封装。


  • UITableViewCell的二次封装(进阶-多态和继承)
    从以上的方法来看,是将原本应该在VC中的cell的实例化的代码封装到了cell里作为类方法来使用,这解决了以下问题:在不同地方用到相同的cell的时候需要写一大段的代码进行变量的声明。但是!这同样会有重复代码的问题,比如,不同的cell,一样会需要写一大段类似的类方法进行声明,如下
    WCBaseTableViewCell
@implementation WCFirstTableViewCell

+ (instancetype)wc_firstTableViewCellWithTableView:(UITableView *)tableView {
    static NSString *ID = @"WCFirstTableViewCell";
    WCFirstTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[WCFirstTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return cell;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self prepareUI];
    }
    return self;
}

- (void)prepareUI {
    
}

@end
@implementation WCSecondTableViewCell

+ (instancetype)wc_secondTableViewCellWithTableView:(UITableView *)tableView {
    static NSString *ID = @"WCSecondTableViewCell";
    WCSecondTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[WCSecondTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return cell;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self prepareUI];
    }
    return self;
}

- (void)prepareUI {
    
}

@end

这是不是又碰到了和上面一样的问题-类似的代码需要重复的写,那么,有没有方法可以避免问题的产生呢?!当然有,这个时候,我们的继承,就发挥出了独特的作用。我们可以设计一个基类(基类拥有一个公共的类方法),让其他的子类继承这个基类,这样就可以避免重复写类似的代码。那么,唯一要解决的两个:

  1. 基类类方法里的cell标识符如何根据不同的子类声明不同
  2. 基类类方法的init类如何显示为字类
    以上两个问题刚好可以用多态来解决!
    WCBaseTableViewCell.m
@implementation WCBaseTableViewCell

+ (instancetype)wc_baseTableViewCellWithTableView:(UITableView *)tableView {
    NSString *ID = NSStringFromClass(self.class);
    WCBaseTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[self.class alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return cell;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self prepareUI];
    }
    return self;
}

- (void)prepareUI {
}

@end

WCBaseTableViewCell.h

@interface WCBaseTableViewCell : UITableViewCell

+ (instancetype)wc_baseTableViewCellWithTableView:(UITableView *)tableView;
- (void)prepareUI;

@end

这样,一个基类就完成了,实战如下
声明一个继承这个基类WCBaseTableViewCell的类
WCThirdTableViewCell.h

#import "WCBaseTableViewCell.h"

NS_ASSUME_NONNULL_BEGIN

@interface WCThirdTableViewCell : WCBaseTableViewCell

@end

NS_ASSUME_NONNULL_END

WCThirdTableViewCell.m

@implementation WCThirdTableViewCell

- (void)prepareUI {
    [super prepareUI];
    self.backgroundColor = [UIColor colorWithRed:random() % 255 / 255.0 green:random() % 255 / 255.0 blue:random() % 255 / 255.0 alpha:1.0];
}

@end

在VC中调用如下
ViewController

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    WCThirdTableViewCell *cell = [WCThirdTableViewCell wc_baseTableViewCellWithTableView:tableView];
    return cell;
}

效果如下


效果图

后续如有要的新的cell,只需要继承WCBaseTableViewCell,然后重写prepareUI方法即可。


此方式的swift版本在后续更新

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容