iOS實現UITableViewDataSource與Controller的分離

寫在前面

在之前的項目中好多處用到了tableView,然而之前不懂得將代理方法實現分離,所以每在一處用到tableView就要在controller中寫一遍UITableViewDataSource和UITableViewDelegate,實現tableView的基本功能中用到的tableViewDelegate的方法還算不太多,但是說到UITableViewDataSource,里面就那些固定的用法,每次都要寫一遍,大大增加了代碼的冗余度,雖然不吝嗇體力多寫幾行代碼,但是給人感覺不太好,接下來就來說一下怎么樣將tableViewDataSource這個磨人的小妖精從controller中分離出來。

創建一個基于NSObject的ArrayDataSource類

這個類就是我們將UITableViewDataSource分離出來所封裝的類。繼承協議@interface ArrayDataSource : NSObject<UITableViewDataSource>
OK,開始我們的分離之路:

1、

首先在.h文件中,我們定義一個block:typedef void (^TableViewCellConfigureBlock)(id cell, id items);
block中需要的兩個參數:第一個參數是cell,第二個參數是數據(這個數據可以是model或者字典)。

2、

在.h文件中寫兩個作為外部調用的接口:
第一個函數:

@param anItems             傳入的盛裝數據的數組
 @param aCellIdentifier     cell的標示符
 @param aConfigureCellBlock 回調的block

- (id)initWithItems:(NSArray *)anItems
     cellIdentifier:(NSString *)aCellIdentifier
 configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock;

第二個函數:
將傳入數組中的數據按照cell的indexPath使用(這個我不知道怎么表述清楚,這個方法就是之前在- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath這個函數中將數組中的數據根據cell的索引值給cell中的控件賦值,不知道這樣說能不能引起大家的共鳴……_

- (id)itemAtIndexPath:(NSIndexPath *)indexPath;
3、

在.m中,我們聲明三個全局變量:

@interface ArrayDataSource ()

@property(nonatomic, strong) NSArray* items;/**< array */
@property(nonatomic, copy) NSString* cellIdentifier;/**< cellIdentifier */
@property(nonatomic, copy) TableViewCellConfigureBlock configureCellBlock;/**< block */

@end

實現.h中的方法:

- (instancetype)init {
    return  nil;
}

調用初始化方法時將外部數據賦值給內部參數
- (id)initWithItems:(NSArray *)anItems cellIdentifier:(NSString *)aCellIdentifier configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock {
    
    self = [super init];
    if (self) {
        self.items = anItems;
        self.cellIdentifier = aCellIdentifier;
        self.configureCellBlock = aConfigureCellBlock;
    }
    return  self;
}
根據cell的索引值,將傳入的數據分離
- (id)itemAtIndexPath:(NSIndexPath *)indexPath {
    return self.items[(NSUInteger) indexPath.row];
}
#pragma mark - UITableViewDataSource
實現UITableViewDataSource的方法。。

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier];
    id item = [self itemAtIndexPath:indexPath];
//在這兒將block傳出。
    self.configureCellBlock(cell, item);
    return cell;
}
在Controller中使用

OK,以上的這個類就是我們分離出來的DataSource的類了

在controller中我使用的假數據,將數據放在一個數組arr中,這里我用到了懶加載,在這里我遇到一個困惑就是為什么在if (!_arr)條件判斷中不能使用self.arr,而只能用_arr,但是在if (!_arr) { self.arr = @[@{@"name":@"實現tableViewController的瘦身"}}]; }中卻可以使用self.arr. 我查了一下資料找到答案,_arr是直接值訪問,而self.arr是屬性訪問,就是通過get/set方法來讀取這個值,xcode會默認將兩個值通過syncthesize關鍵字進行同步,- (NSArray *)arr這個方法就是self.arr的get方法,也就是說每次你調用self.arr的時候都會進入這個方法,如果在這個方法里用了下面這個語句if (!self.arr );邏輯上是行不通的,因為在這里調用self.arr他會再一次進入這個方法,理論上就會死循環,而_arr是直接值訪問的,他不會調用get/set方法,所以就不會有這個問題.
那在if (!_arr) { self.arr = @[@{@"name":@"實現tableViewController的瘦身"}}]; }

- (NSArray *)arr {
    
    if (!_arr) {
        self.arr = @[@{@"name":@"實現tableViewController的瘦身"}}];
    }
    return _arr;
}

我們在controller中使用tableView的時候需要這樣做:

- (void)createTableView {
    
    self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
    [self.tableView registerClass:[LGJTableViewCell class] forCellReuseIdentifier:@"cell"];
    
    self.tableView.rowHeight = 70;
    [self.view addSubview:self.tableView];
    //這里我將block中的第二個參數(id items)傳入了一個字典。因為我的數據是存放在數組中的字典中的。
    TableViewCellConfigureBlock configureCell =^(LGJTableViewCell *cell, NSDictionary *dic) {
        //在這里操作cell中的控件,或者給cell中的控件賦值
        [cell configData:dic];
    };
    self.dateSource = [[ArrayDataSource alloc] initWithItems:self.arr cellIdentifier:@"cell" configureCellBlock:configureCell];
    self.tableView.dataSource = self.dateSource;
}
總結

經過抽取,我們將dataSource從controller中分離出來,這樣不用每次使用tableView的時候我們都要重復寫一遍dataSource代理了,同時也簡化了代碼結構。希望小伙伴們如果覺得有不妥的地方幫我指出來,我們一同進步。end

項目地址:https://github.com/irembeu/DataSourceTableViewTest.git

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容