若是問iOS中最重要的最經常使用的UI控件是什麼,我以爲UITableView當之無愧!彷佛全部常規APP都使用到了UITableView。下面就講一講UITableView的經常使用知識和使用原理及性能優化!css
UITableView繼承於UIScrollview,所以它默認支持垂直滾動(只支持垂直滾動)html
UITableView性能極佳,它能夠出色的完成咱們工做中的不少功能。nginx
UITableView一共有兩種樣式:UITableViewStylePlain 和 UITableViewStyleGroupweb
效果分別如圖:
canvas
UITableViewStylePlain:一種平鋪的效果,而且分組組頭默認有停靠效果;緩存
UITableViewStyleGroup:一種組間分離的效果,每組之間間距較明顯,有明顯分組跡象。ruby
說完了UITableView的簡介,下面來講說他它是如何展現數據的。性能優化
UITableView和數據源的關係以下
markdown
數據源方法的調用過程app
調用以下方法,查詢一共有多少組數據
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
調用以下方法,查詢每一組一共有多少行數據
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
調用以下方法,查詢每一行顯示什麼樣的內容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
UITableView還有一些其餘的數據源方法以下
/** * 返回組頭標題 */ - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; /** * 返回尾標題 */ - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; ···
最簡單的返回UITableViewCell的方法以下
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] init]; cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row]; return cell; }
可是實際使用過程當中這樣是很是耗費性能的,由於當用戶滑動UITableView的時候,上面方法會瘋狂的調用,瘋狂的建立UITableViewCell。
蘋果對這種狀況作了一些性能優化,UITableViewCell在每次建立的時候只會建立當前UI頁面上可見的Cell。當Cell滑動到屏幕外面,當前Cell會被放入到緩存池中,而且能夠給Cell設置一個複用標識,當下次使用Cell的時候能夠先到緩存池中查找,若是有對應複用標識的Cell就直接拿出來使用,並從新給內容賦值。
因此根據蘋果複用Cell的思路咱們在調用返回cell的方法思路應該以下:
因此上面方法從提升性能角度考慮,應該從新寫爲下面這樣:
/** * 何時調用:每當有一個cell進入視野範圍的時候調用 */ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 0.建立cell複用標識 static NSString *reuseIdentifier = @"cell"; // 1.根據複用標識在複用池中進行查找 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; // 2.判斷若是複用池cell爲nil就根據複用標識本身建立 if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; } // 3.拿到cell進行數據覆蓋 cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row]; return cell; }
咱們能夠手動給tableview註冊對應標識的cell,保證從緩存池中能加載到對應標識的cell。
經過代碼註冊
// 註冊cell static NSString *reuseIdentifier = @"cell"; [tableview registerClass:[UITableViewCell class] forCellReuseIdentifier:reuseIdentifier];
經過Xib註冊
// 註冊cell static NSString *reuseIdentifier = @"cell"; // 標識能夠在Xib中建立 [tableview registerNib:[UINib nibWithNibName:@"對應的Xib名稱" bundle:nil] forCellReuseIdentifier:reuseIdentifier];
在數據源方法中返回cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.根據複用標識在複用池中進行查找 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; // 2.拿到cell進行數據覆蓋 cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row]; return cell; }
第三種方式是經過UITableViewController在StoryBoard中建立,見下面:5.UITableViewController
有了數據源方法,tableview就能夠正常展現數據。有了對應的代理方法就能夠正常監聽tableview的事件操做。
下面列舉一些經常使用代理方法:
/** 返回行高,可根據不一樣行返回不一樣高 @param tableView tableview @param indexPath 位置 @return 行高 */ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; /** 返回估計行高,此方法不進行真實計算,課改變Cell計算高度方法的調用順序, @param tableView tableview @param indexPath 位置 @return 行高 */ - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath; /** cell的點擊事件處理 @param tableView tableview @param indexPath 位置 */ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; /** cell將要被選中 -- 先需取消選中某個cell才能正常選中新的cell */ - (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath; /** cell將要被取消選中 */ - (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath ···
UITableViewController繼承自UIViewController。能夠方便建立有tableview的控制器
在StoryBoard中建立UITableViewController並加載cell步驟以下:
設置Dynamic Prototypes動態類型的內容,下面數量至少爲1
設置cell的複用標識identfier
在代碼中直接加載對應cell便可(無需判空/建立)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.會默認去緩存池中進行查找,若是沒有自動去StoryBaord中找 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; // 2.拿到cell進行數據覆蓋 cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row]; return cell; }
經過StoryBoard建立Cell更加方便
小結