亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS中的UITableView的重用機制與加載優化詳解

2020-07-26 02:57:06
字體:
來源:轉載
供稿:網友

UITableView可以說是UIKit中最重要的一個組件,用來展示數據列表,還可以靈活使用進行頁面的布局。UITableView的使用遵循MVC模式,數據模型(NSObject)、視圖(UIView)和控制器(UITableViewController)分離。UITableView繼承自UIScrollView,可上下滑動,可以作為跟視圖也可以作為子視圖組件。

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的一個數據存到數據庫供隨時取用。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美性猛交xxxx乱大交蜜桃| 国产suv精品一区二区| 欧美激情国产精品| 欧美激情亚洲激情| 国产精品美女久久久久久免费| 亚洲区一区二区| 精品国产一区二区三区久久狼5月| 国产日韩欧美中文在线播放| 精品国产欧美一区二区三区成人| 亚洲在线第一页| 国产精品三级在线| 国产精品白丝jk喷水视频一区| 欧美日韩综合视频| 668精品在线视频| 久久露脸国产精品| 日韩欧美在线播放| 欧美疯狂xxxx大交乱88av| 亚洲一品av免费观看| 国产精品1区2区在线观看| 日韩中文字幕在线精品| 黑丝美女久久久| 亚洲天堂成人在线| 日韩中文字幕av| 黄网动漫久久久| 日韩中文视频免费在线观看| 亚洲精品一区二区三区不| 性金发美女69hd大尺寸| 欧美亚洲国产精品| 欧美激情一区二区三区成人| 亚洲人成在线免费观看| 久久久精品欧美| 欧美一级大片视频| 亚洲成av人影院在线观看| 日韩精品一二三四区| 国产va免费精品高清在线观看| 欧美电影免费在线观看| 在线成人一区二区| 91免费在线视频网站| 国产精品户外野外| 日本欧美黄网站| 色先锋资源久久综合5566| 亚洲精品久久久久久下一站| 亚洲日本aⅴ片在线观看香蕉| 2018中文字幕一区二区三区| 国产激情久久久| 国产美女搞久久| 亚洲欧美另类人妖| 久久久久久国产精品| 亚洲黄色成人网| 91久久国产综合久久91精品网站| 中文字幕亚洲图片| 青青青国产精品一区二区| 国产97人人超碰caoprom| 国内精品久久久久久久久| 成人免费视频a| 亚洲天堂免费视频| 国产美女被下药99| 日韩电影第一页| 自拍偷拍亚洲区| 久久久久久91| 久久精品久久久久电影| www.亚洲人.com| 在线国产精品视频| 亚洲天堂av在线免费观看| 日韩高清免费在线| 孩xxxx性bbbb欧美| 亚洲国产成人在线播放| 亚洲一区二区精品| 97国产精品免费视频| 亚洲免费视频观看| 国产日产久久高清欧美一区| 国产女精品视频网站免费| 国产一区二区三区中文| 久久久久久久久中文字幕| 国产成人精品亚洲精品| 亚洲图片欧美午夜| 精品久久久久久久久久国产| 欧美性理论片在线观看片免费| 欧美在线一级va免费观看| 51ⅴ精品国产91久久久久久| 成人精品久久av网站| 欧美精品少妇videofree| 韩国19禁主播vip福利视频| 日韩高清免费观看| 成人乱人伦精品视频在线观看| 久久久久免费精品国产| 日韩二区三区在线| 亚洲精品国精品久久99热| 欧美性生交大片免费| 午夜剧场成人观在线视频免费观看| 欧美激情精品久久久久久变态| 久久久免费电影| 日本精品视频在线| 高清日韩电视剧大全免费播放在线观看| 欧美成人久久久| 伊人久久久久久久久久久久久| 中国人与牲禽动交精品| 欧美精品午夜视频| www欧美日韩| 在线免费观看羞羞视频一区二区| 国产成人中文字幕| 色在人av网站天堂精品| 精品国偷自产在线| 日韩精品视频观看| 97久久超碰福利国产精品…| 国产玖玖精品视频| 欧美电影在线观看完整版| 欧美大片大片在线播放| 大伊人狠狠躁夜夜躁av一区| 亚洲成人av在线播放| 久久av资源网站| 日韩电影中文字幕av| 欧美中文字幕视频在线观看| 国产视频欧美视频| 色偷偷av一区二区三区乱| 亚洲欧美日韩精品久久亚洲区| 日韩黄色高清视频| 欧美国产日韩一区二区三区| 欧美电影在线观看网站| 日韩av在线网站| 久久韩剧网电视剧| 亚洲免费av电影| 国产欧美一区二区三区四区| 久久久久久久久久久av| 久久视频免费在线播放| 日韩网站免费观看高清| 最好看的2019年中文视频| 91久久国产婷婷一区二区| 91沈先生在线观看| 亚洲国产成人久久综合一区| 亚洲欧美在线一区二区| 国产成人一区二区| 中文字幕成人在线| 亚洲第一男人天堂| 久久久久国产精品www| 午夜精品一区二区三区在线视| 91影院在线免费观看视频| 伊人久久男人天堂| 欧美激情精品久久久| 国产精品久久久久久av福利| 亚洲欧洲日本专区| 欧美老女人在线视频| 91禁国产网站| 亚洲精品电影网在线观看| 欧美一区二区大胆人体摄影专业网站| 亚洲精品日韩激情在线电影| 国产最新精品视频| 久久久国产在线视频| 色偷偷噜噜噜亚洲男人的天堂| 国产视频丨精品|在线观看| 日韩中文字幕视频| 欧美性在线观看| 美女久久久久久久久久久| 色琪琪综合男人的天堂aⅴ视频| 色吧影院999| 亚洲区免费影片| 日韩在线视频观看| 亚洲精品福利在线| 国产成人精品在线| 国产精品日韩在线| 91国偷自产一区二区三区的观看方式| 狠狠综合久久av一区二区小说| 狠狠色狠狠色综合日日小说| 亚洲精品午夜精品|