UITableView可以說是UIKit中最重要的一個組件,用來展現數據列表,還可以靈敏運用停止頁面的規劃。UITableView的運用遵照MVC形式,數據模型(NSObject)、視圖(UIView)和控制器(UITableViewController)別離。UITableView承繼自UIScrollView,可上下滑動,可以作為跟視圖也可以作為子視圖組件。
UITableViewController中,創立UITableViewCell時,initWithSytle:resuseIdentifier中,reuseIdentifier有什麼用?UITableViewCell的復用原理?reuseIdentifier望文生義是一個復用標識符,是一個自定義的無獨有偶的字符串,用來獨一地標志某種反復款式的可復用UITableViewCell,零碎是經過reuseIdentifier來確定曾經創立了的指定款式的cell來停止復用,IOS中表格的cell經過復用來進步加載效率,由於少數狀況下表格中的cell款式都是反復的,只是數據模型不同而已,因而零碎可以在保證創立足夠數量的cell鋪滿屏幕的前提下,經過保管偏重復運用曾經創立的cell來進步加載效率和優化內存,防止不停地創立和銷毀cell元素。
UITableViewCell的復用原理其實很復雜,可以經過上面一個復雜的例子來了解:
首先在開發中我們在UITableViewController類中寫cell復用代碼的最根本模板會像上面這樣:
/**
* 可復用cell制造
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// 定義cell重用的靜態標志符
static NSString *cell_id = @"cell_id_demo";
// 優先運用可復用的cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cell_id];
// 假如要復用的cell還沒有創立,則創立一個供之後復用
if (cell == nil) {
// 新創立cell並運用cell_id復用符標志
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_id];
}
// 配置cell數據
cell.textLabel.text = [NSString stringWithFormat:@"Cell%i", countNumber];
// 其他cell設置...
return cell;
}
代碼這樣寫的緣由是經過調用以後tableView的dequeueReusableCellWithIdentifier辦法看指定的reuseIdentifier能否有可以反復運用的了,假如有則會前往可復用的cell,cell就緒之後便可以開端更新cell的數據;假如還不可復用,則前往nil,然後會進入前面的if語句,此時創立新的cell並對其設置cell款式標志reuseIdentifier。留意下面的if語句並不是只需執行一次創立一次新的cell就完成義務,然後之後全部反復應用新創立的那一個cell,這是對cell復用機制的曲解。現實是要創立足夠數量的可掩蓋整個tableView的可復用cell之後才會開端復用之前的(UITableView中有一個visiableCells數組保管以後屏幕可見的cell,還有一個reusableTableCells數組用來保管那些可復用的cell),這個我們用上面的測試來驗證。
如何簡約清楚的展現UITableViewCell的復用機制呢?這裡的辦法是創立最根本的文本cell,並創立一個cell創立計數器,每次新創立cell計數器加1並顯示在cell上,假如是復用的cell則會顯示是復用的哪一個cell,測試代碼如下:
/**
* 分區個數設置為1
*/
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
/**
* 創立20個cell,保證掩蓋並超出整個tableView
*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
/**
* cell復用機制測試
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// 定義cell重用的靜態標志符
static NSString *cell_id = @"cell_id_demo";
// 計數用
static int countNumber = 1;
// 優先運用可復用的cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cell_id];
// 假如要復用的cell還沒有創立,則創立一個供之後復用
if (cell == nil) {
// 新創立cell並運用cell_id復用符標志
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_id];
// 計數器標志新創立的cell
cell.textLabel.text = [NSString stringWithFormat:@"Cell%i", countNumber];
// 計數器遞增
countNumber++;
}
return cell;
}
運轉在iPhone5S設備上(UITableViewController作為跟控制器,tableView掩蓋整個屏幕),20個cell顯示後果順次為:
Cell1、Cell2、Cell3、Cell4、Cell5、Cell6、Cell7、Cell8、Cell9、Cell10、Cell11、Cell12、Cell13、Cell14、Cell1、Cell2、Cell3、Cell4、Cell5、Cell6
可以看出一共創立了14個cell,其中整個屏幕可顯示13個cell,零碎多創立一個的緣由是保證在表格滑動顯示半個cell時依然能掩蓋整個tableView。之後的6個cell就是復用了開端創立的那6個cell了。這樣UITableViewCell復用的根本機制就很清楚了,另外還會有reloadData或許reloadRowsAtIndex等刷新表格數據的狀況,能夠會隨同新的cell創立和可復用cell的更新,但也是樹立在根本復用機制的根底之上的。
能否在一個視圖控制器中嵌入兩個tableview控制器?可以,相當於視圖以及視圖控制器的嵌套,視圖可以添加子視圖,視圖控制器也可以添加子控制器。這麼問應該是由於這種狀況有時會用到而且很重要,由於有一點容易被無視,就是將子視圖添加到了父視圖卻遺忘將對應的控制器作為子控制器添加到父控制器,招致子視圖能顯示但是不能呼應(沒有對接好控制器)。例如在以後視圖上放一個小尺寸的表格組件,也就是在UIViewController上添加一個UITableViewController子控制器及其子view:
// 假定有三個視圖控制器,一個作為父控制器,兩個作為子控制器
UIViewController *superVC = [[UIViewController alloc]init];
UITableViewController *subVC1 = [[UITableViewController alloc]init];
UITableViewController *subVC2 = [[UITableViewController alloc]init];
// 將子視圖控制器添加到父視圖控制器(要留意調整子視圖的尺寸和地位合理顯示,這裡疏忽)
[superVC.view addSubview:subVC1.view];
[superVC addChildViewController:subVC1];
[superVC.view addSubview:subVC2.view];
[superVC addChildViewController:subVC2];
// 子視圖控制器的移除有對稱的辦法,但只能是子視圖控制器自動從父視圖控制器中移除
[subVC1.view removeFromSuperview];
[subVC1 removeFromParentViewController];
[subVC2.view removeFromSuperview];
[subVC2 removeFromParentViewController];
此外要留意和presentViewController函數添加子視圖控制器的區別,下面手動添加子視圖控制器是可以自在調整子視圖的frame的(包括子視圖地位和尺寸),而presentViewController是用於頁面切換,切換後的子頁面會掩蓋整個屏幕而不可以自在調整子頁面地位和尺寸,對稱的子視圖控制器移除辦法為dismissViewControllerAnimated:
// 顯示子視圖控制器,completion後的代碼塊假如不為空添加完畢後會觸發
[[parentVC presentViewController:childVC animated:NO completion:nil];
// 移除子視圖控制器,completion後的代碼塊假如不為空添加完畢後會觸發
[childVC dismissViewControllerAnimated:NO completion:nil];
一個tableView能否可以關聯兩個不同的datasource數據源?如何處置?
多個數據源是完全可以的,關鍵是如何關聯,問題的重點是如何處置,由於將數據源(Model)和tableview視圖(View)的對接任務是順序員完成的,因而數據源的多少沒有基本影響。處置上可以分開順次對接,也可以經過數據的集合操作先將數據整理兼並成一個數據源然後對接。
例如:一個表格中的每個cell顯示的是一團體的根本信息,為了復雜這裡假定只要一個頭像和一個姓名。假定有兩個數據源,一個數據源是頭像的url數組,一個是姓名的字符串數組,對接時完全可以分開在cell數據回調中對接,也可以將兩個數組兼並然後對接。
兼並數據用到的數據模型:
@interface Model : NSObject
@property (nonatomic,copy) NSString *name; // 姓名
@property (nonatomic,copy) NSString *url; // 圖片
@end
數據源緩沖器:
// 數據源
@property (nonatomic, strong)NSArray *name_datasource;
@property (nonatomic, strong)NSArray *url_datasource;
@property (nonatomic, strong)NSMutableArray *datasource;
處置少數據源:
/**
* 懇求數據
*/
- (void)request {
// 姓名數據源
_name_datasource = @[@"張三", @"李四", @"小明", @"小李"];
_url_datasource = @[@"male", @"male", @"male", @"male"];
// 兼並數據源
for (int i; i<_name_datasource.count; i++) {
Model *model = [[Model alloc]init];
model.name = _name_datasource[i];
model.url = _url_datasource[i];
[_datasource addObject:model];
}
}
數據對接:
/**
* cell數據回調
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = @"identifier";
// 自制cell組件
AccountCell *cell = [[AccountCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
/** 少數據源分開對接:**/
// 頭像
[cell.avatar setImage:[UIImage imageNamed:_url_datasource[indexPath.row]]];
// 姓名
cell.name.text = _name_datasource[indexPath.row];
// 或許:
/** 數據源兼並後對接**/
// 取出對應數據模型
Model *model = _datasource[indexPath.row];
// 頭像
[cell.avatar setImage:[UIImage imageNamed:model.url]];
// 姓名
cell.name.text = model.name;
return cell;
}
如何對UITableView的滾動加載停止優化,避免卡頓?
UITableView的滾動優化次要在於以下兩個方面:
增加cellForRowAtIndexPath代理中的計算量(cell的內容計算) 增加heightForRowAtIndexPath代理中的計算量(cell的高度計算) 增加cellForRowAtIndexPath代理中的計算量 首先要提早計算每個cell中需求的一些根本數據,代理調用的時分直接取出; 圖片要異步加載,加載完成後再依據cell外部UIImageView的援用設置圖片; 圖片數量多時,圖片的尺寸要跟據需求提早經過transform矩陣變換緊縮好(直接設置圖片的contentMode讓其自行緊縮依然會影響滾動效率),必要的時分要預備好預覽圖和高清圖,需求時再加載高清圖。 圖片的‘懶加載’辦法,即延遲加載,當滾動速度很快時防止頻繁懇求服務器數據。 盡量手動DraWing視圖提升流利性,而不是直接子類化UITableViewCell,然後掩蓋drawRect辦法,由於cell中不是只要一個contentview。繪制cell不建議運用UIView,建議運用CALayer。緣由要參考UIView和CALayer的區別和聯絡。 增加heightForRowAtIndexPath代理中的計算量 由於每次TableView停止update更新都會對每一個cell調用heightForRowAtIndexPath代理獲得最新的height,會大大添加計算時間。假如表格的一切cell高度都是固定的,那麼去掉heightForRowAtIndexPath代理,直接設置TableView的rowHeight屬性為固定的高度; 假如高度不固定,應盡量將cell的高度數據計算好並貯存起來,代理調用的時分直接取,行將height的計算時間復雜度降到O(1)。例如:在異步懇求服務器數據時,提早將cell高度計算好並作為dataSource的一個數據存到數據庫供隨時取用。【【iOS深思錄】UITableView的重用機制與加載優化步驟】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!