概念
封裝:提供可以調用的接口,隱藏具體實現方案
繼承:子類擁有父類的成員變量和方法,可以較大程度減少代碼的重復率
多態(tài):父類指針指向子類對象(實例對象調用的方法會尋找到真實的類進行調用)
應用
封裝一個常用的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創(chuàng)建的過程來看(如下)
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的二次封裝(進階-多態(tài)和繼承)
從以上的方法來看,是將原本應該在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
這是不是又碰到了和上面一樣的問題-類似的代碼需要重復的寫,那么,有沒有方法可以避免問題的產生呢?!當然有,這個時候,我們的繼承,就發(fā)揮出了獨特的作用。我們可以設計一個基類(基類擁有一個公共的類方法),讓其他的子類繼承這個基類,這樣就可以避免重復寫類似的代碼。那么,唯一要解決的兩個:
- 基類類方法里的cell標識符如何根據不同的子類聲明不同
- 基類類方法的init類如何顯示為字類
以上兩個問題剛好可以用多態(tài)來解決!
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
這樣,一個基類就完成了,實戰(zhàn)如下
聲明一個繼承這個基類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;
}
效果如下

后續(xù)如有要的新的cell,只需要繼承WCBaseTableViewCell,然后重寫prepareUI方法即可。
此方式的swift版本在后續(xù)更新