正確使用Block避免迴圈引用(二)
在客戶端app開發中一般都採用的是MVC(model,view,controller的簡稱)的分層開發模式,目的是降低程式碼之間的耦合度,提高程式碼複用率,以及更便於後期的程式碼維護,好處不多說。往往開發中在Controller層往往是程式碼堆砌最多的地方,應該可以抽離到view層的程式碼,可以抽離到model層的程式碼全都耦合在Controller層,使得Controller層變得非常臃腫,程式碼可閱讀性變的很差,找個方法都要半天的時間,專案開發和維護都會為之損耗很多不必要的時間,養成一個好的程式設計習慣對你的程式設計水平提高,對團隊都是大有益處的!廢話不多說,進入正題。
自己使用Block封裝了一個TableView的萬能資料來源,只要是使用到動態TableView,都可以使用,用來抽離耦合在Controller層的資料來源委託協議中的實現程式碼。下面是具體程式碼:
#import <Foundation/Foundation.h>
#import "TableViewDataSource.h"
@interface TableViewDataSource(){
TableViewCellConfigBlock _cellConfigBlock;
NumberOfSectionsConfigBlock _numberOfSectionsConfigBlock;
NumberOfRowsInSectionConfigBlock _numberOfRowsInSectionConfigBlock;
}
@end
@implementation TableViewDataSource
-(void)clearConfigBlock{
_cellConfigBlock = nil;
_numberOfSectionsConfigBlock = nil;
_numberOfSectionsConfigBlock = nil;
}
-(instancetype)initWithNumberOfSectionsConfigBlock:(NumberOfSectionsConfigBlock)numberOfSectionsConfigBlock
numberOfRowsInSectionConfigBlock:(NumberOfRowsInSectionConfigBlock)numberOfRowsInSectionConfigBlock
tableViewCellConfigBlock:(TableViewCellConfigBlock)configBlock{
self = [super init];
if (self) {
_cellConfigBlock = [configBlock copy];
_numberOfSectionsConfigBlock = [numberOfSectionsConfigBlock copy];
_numberOfRowsInSectionConfigBlock = [numberOfRowsInSectionConfigBlock copy];
}
return self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
//回撥block
return _numberOfRowsInSectionConfigBlock(tableView, section);
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
//回撥block
return _numberOfSectionsConfigBlock(tableView);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//回撥block
return _cellConfigBlock(tableView, indexPath);
}
@end
具體在Controller層的使用,有兩個關鍵點:
很多寶寶也嘗試自己封裝一個充當資料來源的類,但是在具體使用中,出現了委託協議中的方法不執行的情況,出現這個問題一般有如下兩個原因:
一:
沒有給TableView物件設定資料來源委託物件
self.myTableView.dataSource = ....(檢查是否設定)
二:
一定要把自己封裝的資料來源物件作為VC類的成員屬性,切勿在方法體中作為臨時物件進行建立,因為委託資料來源的生命週期是要和TableView例項物件的生命週期保持一致的,要是充當資料來源委託的物件早早就掛了,tableview不顯示任何資料那是一定的,具體下面程式碼中有具體講解。
#import <Foundation/Foundation.h>
#import "MYTableViewController.h"
#import "TableViewDataSource.h"
@interface MYTableViewController()
@property(nonatomic,strong)NSArray *dataArr;
@property(nonatomic,weak)IBOutlet UITableView *myTableView;
@property(nonatomic,strong)TableViewDataSource *myDataSource;
@end
@implementation MYTableViewController
-(void)viewDidLoad{
[self initDataArr];
[self initDataSource];
//注意先後順序
_myTableView.dataSource = _myDataSource;
}
#pragma mark---初始化資料
-(void)initDataArr{
_dataArr = [NSArray arrayWithObjects:@"藍色",@"綠色",@"黑色",@"白色",@"橘色", nil];
}
#pragma mark---初始化資料來源
-(void)initDataSource{
//很多寶寶想在VC(檢視控制器)分離資料來源委託實現程式碼,達到給給VC瘦身的效果
//別問我為什麼把自己建立的資料來源物件(myDataSource)作為類的成員屬性,目的是控制資料來源物件的生命週期跟VC物件的生命週期一致
//假使你把資料來源物件宣告成方法體內的臨時物件,那麼會出現資料來源委託協議中的方式是不會被執行的,myTableView中是不會顯示任何資料的(不信你可以試試)
//原因很簡單:因為被宣告為方法內部的臨時資料來源物件會隨著方法執行完畢後而被釋放,出了方法體相當於:(self.myTableView.dataSource=nil),資料來源委託協議中的方法壓根沒機會被執行!!!
//TableViewDataSource *myDataSource = .......(千萬別把資料來源物件作為方法內部的區域性物件進行建立,切忌!!!)
__weak typeof (self) weakSelf = self;//(這是必須的)
_myDataSource = [[TableViewDataSource alloc]initWithNumberOfSectionsConfigBlock:^NSInteger(UITableView *tableView) {
return 1;
} numberOfRowsInSectionConfigBlock:^NSInteger(UITableView *tableView, NSInteger section) {
//return [_dataArr count];//(注意避免迴圈引用的發生)
return [weakSelf.dataArr count];
} tableViewCellConfigBlock:^UITableViewCell *(UITableView *tableView, NSIndexPath *indexPath) {
UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"reuseId"];
if (!cell) {
cell = [[UITableViewCell alloc]initWithFrame:CGRectZero];
}
//cell.textLabel.text = [_dataArr objectAtIndex:indexPath.row];//(注意避免迴圈引用的發生)
cell.textLabel.text = [weakSelf.dataArr objectAtIndex:indexPath.row];
return cell;
}];
}
-(void)dealloc{
NSLog(@"執行解構函式");
}
@end
上一篇文章中講到了,怎麼測試程式碼中是否出現迴圈引用的方法:
就是在NavigationController控制器中pop掉當前頁面的時候,看看當前VC中的dealloc(解構函式)是否被執行,如果執行,說明沒有其他物件引用當前VC物件,自然不會有迴圈引用的發生,假如沒有被執行,那就要好好檢查程式碼,八九不離十出現了迴圈引用的情況,導致VC的retainCount>1,得不到釋放,想自己測試就下載專案自己跑吧。
下面把是程式碼下載地址,可以自行下載:
下載