tableView入門到性能優化

標籤(空格分隔): UITableView UITableViewCell UITableView性能優化 UITableView性能優化精講面試


參考文章編程

摘要:UITableView是iOS開發中很是重要的控件之一,它可以展現多行數據,支持滾動.在大部分APP中都佔有很大的比重.那麼有關UITableView的性能優化也顯得尤其重要,本文後面也將着重講這個。數組

##UITableView的簡單使用 ###一、UITableView的建立緩存

代碼方式性能優化

//tableView的建立必須制定一個樣式,樣式在初始化以後不能修改
//tableView分兩種風格,Plain:不分區,grouped:分區
_tableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
    _tableView.delegate = self;
    _tableView.dataSource = self;
//告訴tableView,它上面的cell是根據UItableViewCell建立的,若是重用的cell找不到,系統會根據這個類來建立一個cell,不須要編程人員建立
//解釋2://給tableView的某個重用標示符註冊一個類,當tableView找這個重用標示符的cell,若是找不到,就會自動建立這個類的對象,(始終能找到可重用的cell)
    [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
    [self.view addSubview:_tableView];
複製代碼

xib方式 在設計界面拖入,並在屬性檢查器中設置各類屬性bash

###二、UITableView的屬性網絡

// 設置每一行cell的高度
    self.tableView.rowHeight = 80;
// 設置每一組的頭部標題高度
    self.tableView.sectionHeaderHeight = 50;
// 設置每一組的尾部標題高度
    self.tableView.sectionFooterHeight = 50;
// 設置分割線的顏色
    self.tableView.separatorColor = [UIColor redColor];
// 設置分割線的樣式
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
// 設置表頭控件---這裏主要應用是打廣告
    self.tableView.tableHeaderView = [[UISwitch alloc] init];
// 設置表尾控件---這裏主要應用是加載數據
    self.tableView.tableFooterView = [[UISwitch alloc] init];
// 設置索引條的文字顏色
    self.tableView.sectionIndexColor = [UIColor orangeColor];
// 設置索引條的背景顏色
    self.tableView.sectionIndexBackgroundColor = [UIColor yellowColor];
複製代碼

###三、隱藏TableView分割線的方法app

// 方法一:設置分割線的顏色
    self.tableView.separatorColor = [UIColor clearColor];
// 方法二:設置分割線的樣式
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
複製代碼

###四、UITableViewCell的屬性佈局

//cell中默認包含的空間
cell.imageView
cell.textLabel
cell.detaliTextLabel
cell.contentView
// 設置右邊顯示的指示控件
// accessoryView的優先級 > accessoryType
cell.accessoryView = [[UISwitch alloc] init];

// 設置右邊顯示的指示樣式
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

// 設置cell選中的樣式
// 設置cell的選中樣式無
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// 下面三種方式在iOS7以後,表現形式同樣了,都是灰色
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
複製代碼

###五、設置cell的背景顏色性能

// 整體效果爲大背景藍色,字體背景爲紅色,下面代碼能夠調換順序,效果同樣
cell.backgroundColor = [UIColor redColor];

UIView *bg = [[UIView alloc] init];
bg.backgroundColor = [UIColor blueColor];
cell.backgroundView = bg;
複製代碼

###六、設置cell選中的背景View

// 設置cell選中的背景view
    UIView *seletedBg = [[UIView alloc] init];
    seletedBg.backgroundColor = [UIColor yellowColor];
    cell.selectedBackgroundView = seletedBg;
複製代碼

###七、兩個協議

tablewView代理方法的執行順序。 UITableView返回多少組----->每組返回多少行cell--->計算每一個cell的高度---->指定cell佈局

UITableViewDelegate

/**
 *  1.當用戶點擊(選中)某一行cell就會調用這個方法
 */
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"選中了:%zd",indexPath.row);
}

/**
 *  2.當用戶取消點擊(選中)某一行cell就會調用這個方法
 */
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"取消選中了:%zd",indexPath.row);
}

/**
 *  3.返回每一組的頭部高度
 */
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{

}

/**
 *  4.返回每一組的尾部高度
 */
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{

}

/**
 *  5.返回每一行cell的高度
 */
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row % 2 == 0) {
        return 50;
    } else {
        return 100;
    }
}

/**
 *  6.返回每一組的頭部控件
 */
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    return [UIButton buttonWithType:UIButtonTypeContactAdd];
}

/**
 *  7.返回每一組的尾部控件
 */

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    return [UIButton buttonWithType:UIButtonTypeContactAdd];
}
/*
* 8.設置每一行的編輯樣式:當表處於編輯狀態時,默認的編輯樣式爲刪除
*/
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView 		editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
		{
			 //編輯狀態爲刪除
   		 return UITableViewCellEditingStyleDelete;
   		 //編輯狀態爲插入
    		 //return UITableViewCellEditingStyleInsert;
		}
		
//經過edditing的值來顯示編輯狀態
_tableView.editing = !_tableView.editing;


/*
*  9.表提交編輯狀態的時候會調用這個方法
*/
-(void)tableView:(UITableView *)tableView commitEditingStyle:	(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath 	*)indexPath
	{
	    [_dataArray removeObjectAtIndex:indexPath.row];
	    [_tableView reloadData];
	}
/*
*  10.設置編輯中刪除的文字
*/
-(NSString *)tableView:(UITableView *)tableView 	titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath 	*)indexPath
{
	return @"走你";
}
/*
*  11.右側按鈕被點擊時會調用該方法
*/
	-(void)tableView:(UITableView *)tableView 	accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
	{
  		 NSLog(@"調用了cell右側按鈕的方法");
	}



複製代碼

###八、兩個協議二:UITableViewDataSources

/**
 *  告訴tableView一共有多少組數據
 */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView


/**
 *  告訴tableView第section組有多少行
 */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

/**
 *  告訴tableView每一行顯示的內容(tableView每一行的內容是是第一個UITableViewCell)
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

/**
 *  告訴tableView每一組的頭部標題
 */
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

/**
 *  告訴tableView每一組的尾部標題
 */
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section

/**
 *  返回索引條的文字
 */
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
//    NSMutableArray *titles = [NSMutableArray array];
//    for (XMGCarGroup *group in self.carGoups) {
//        [titles addObject:group.title];
//    }
//    return titles;

// 抽取self.carGoups這個數組中每個元素(XMGCarGroup對象)的title屬性的值,放在一個新的數組中返回
    return [self.carGoups valueForKeyPath:@"title"];
複製代碼

##2、UITableViewCell 在UITableView中,每個單元格被稱爲cell,若是想在UITableView中顯示數據,須要設置UITableView中cell的數量及每一個cell顯示的內容.UITableView並不能直接顯示數據,它須要設置數據源(datasource),數據源遵照協議,並實現其中對應的方法設置數據及內容便可. ###UITableViewCell的建立

  1. 設置Cell的三個屬性

    cell.imageView     //cell左邊的圖片
    cell.textLabel		  
    cell.detailTextLabel
    複製代碼
  2. 經過自定義類 建立一個累繼承於UITableViewCell,添加以下屬性

    @property (nonatomic,retain)UIImageView *headerImageView;
    @property (nonatomic,retain)UILabel *nameLabel;
    @property (nonatomic,retain)UILabel *timeLabel;
    @property (nonatomic,retain)UILabel *messageLabel;
    @property (nonatomic,retain)UIImageView *picImageView;
    複製代碼

    .m文件中的實現

    //若是是alloc建立的cell,各個自定義屬性空間的初始化代碼寫在init方法中
    (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString 	*)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
            //頭像
        _headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(8, 8, 60, 60)];
        _headerImageView.layer.cornerRadius = 30;
        _headerImageView.layer.masksToBounds = YES;
        [self.contentView addSubview:_headerImageView];       
        //名字
        _nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(76, 8, 240, 20)];
        _nameLabel.font = [UIFont boldSystemFontOfSize:16];
        _nameLabel.textColor = [UIColor redColor];
        [self.contentView addSubview:_nameLabel];   
        //發佈時間
        _timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(76, 36, 240, 20)];
        _timeLabel.font = [UIFont systemFontOfSize:12];
        [self.contentView addSubview:_timeLabel];        
        //動態正文
        _messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 76, 304, 60)];
        _messageLabel.font = [UIFont systemFontOfSize:16];       
        //numberOfLines行數,設置爲0不限制行數。
        _messageLabel.numberOfLines = 0;        
        [self.contentView addSubview:_messageLabel];        
        //動態配圖
        _picImageView = [[UIImageView alloc] initWithFrame:CGRectMake(8, 144, 100,100)];
        [self.contentView addSubview:_picImageView];
        }
        return self;
        }	
    複製代碼
  3. 經過xib自定義 首先建立一個帶xib的UITableViewCell,拖控件設置cell高度。拉線生成屬性;

自定義類中
     //若是cell是從xib中加載的,那麼不走init方法,因此初始化代碼不能寫在init方法中
		//當自身從xib中加載的時候調用,因此自定義xib的代碼應該在這裏實現
		(void)awakeFromNib {
    		[super awakeFromNib];
   	 // Initialization code
    		_headerImageView.layer.cornerRadius = 30;
   	 _headerImageView.layer.masksToBounds = YES;
		}
複製代碼

註冊重用

```
//給TableView的某個重用標示符註冊一個xib,當tableView找這個標識符時,若是找不		    到,就會自動從註冊的西邊中區加載一個cell。
[_tableView registerNib:[UINib nibWithNibName:@"CustomCell" 		bundle:nil]     forCellReuseIdentifier:@"cell"];
```
複製代碼

##3、性能優化

1)儘可能使用cell的複用。

使用cell的複用,能夠減小內存的開銷,沒有開闢新的空間,也減小了一些計算量。

複用原理:當滾動列表時(UITableView)部分cell會移除Window 可是移除的cell並無被當即釋放 而是放到了一個叫作複用池的對象池中,處於待定狀態,當有新的cell要出如今Window界面上時,首先會從複用池中尋找是否有相同類型的cell,若是有直接拿過用(最直觀的表現是新出現的cell有沒有開闢新的內存空間),若是沒有,建立一個新的類型的cell,因此UITableView可能擁有多種類型的cell,複用池也可能存儲着多種類型的cell,系統經過定義reuseIndentifer做爲每一個cell的惟一標示符來肯定即將出現的cell複用何種類型的cell。

2)對於不定高的cell 提早將每一個cell的高度存入數組,出現一個cell的時候,直接從數組中拿出確切的高度便可,不用臨時計算cell的高度。對於固定高的cell和不定高的cell一樣適用。一樣也能夠在存儲在model中,在獲取數據後要賦值給model時進行計算。

3)涉及網絡請求加載數據在UITableView滑動結束的時候在進行加載數據(渲染)避免卡頓。

一、UITableView繼承自UIScrollView,繼承了後者的方法。
//滑動結束的方法
- (void)scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate:(BOOL)decelerate
//減速結束以後的方法
- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView

二、在tableView必須實現的二個方法中(加載cell的方法中)將數據的渲染寫在如下if語句中
if(self.tableView.dragging==NO&&self.tableView.decelerating==NO)
複製代碼

4)對於tableView的自定義控件 尤爲是UIImageView,儘可能減小使用圓角,陰影等layer屬性,儘可能減小使用alpha(透明度)來設置透明度,(在項目開發中,讓UI設計師設計原圖就是帶圓角的圖) 陰影,圓角這些layer效果都是在GPU中完成的。

一、當多個視圖重疊時,一個像素同時屬於不少subviews,GPU會進行合成渲染,須要渲染一個像素兩次或屢次,而渲染的最慢的操做就是混合。所以當視圖結構太過複雜,就會大量消耗GPU的資源。因此當一個空間自己是不透明,注意設定alpha爲1,這樣能夠避免無用的alpha通道合成,下降GPU的負載。 另外在layer層渲染圖層時會涉及上下文切換以及離屏渲染之類的,系統開銷會很大,特別是在cell視圖很複雜的時候,因爲渲染問題致使的內存開銷會讓你的tableview很是卡頓。好比cell中須要設置頭像圓形直接設置圓角會很卡,那麼咱們能夠用Quartz2d把拿到的圖片處理一遍在給cell使用。

二、對控件設置cornerRadius後對其進行clip或mask操做時 會致使offscreenrendering這個也是在GPU中進行的 若是在滑動時 圓角對象太多 回到GPU的負載大增幅。

這時咱們能夠設置layer的shouldRasterize屬性爲YES,能夠將負載轉移給CPU,更完全的是直接使用帶圓角的原圖。

5)儘可能使用懶加載

懶加載又稱爲延遲加載,其實是重寫某個對象的getter方法 原理:程序一開始並不對它進行初始化 而是在用到他的時候 才爲他開闢內存供它使用。

好處:

一、沒必要將建立的對象的代碼所有寫在ViewDidLoad中,代碼可讀性強。 二、每一個控件的getter方法,分別負責各自的實例化處理,代碼彼此之間獨立性強 鬆耦合。

6)減小返回給的cell裏面的處理邏輯和處理時間。

以驢媽媽爲例:各個UI控件整合到一塊兒,實際上只有一個控件。

7)設置每一個cell的opaque屬性 ----面試亮點

opaque意思是不透明的 渾濁的 有YES和NO二個結果,若是控件自己不透明,咱們設置opaque爲YES。

opaque爲YES表示告訴iOS當前視圖背後沒有須要繪製的內容,同時容許iOS的繪圖方法經過一些優化來加速當前視圖的繪製。

爲何咱們設置Alpha的值爲1的時候仍然要設置opaque的屬性爲YES? Alpha屬性只對當前須要繪製的視圖起做用,若是當前視圖並無填滿父視圖或者當前視圖上存在一些洞(由Alpha通道所致),那麼圖像視圖下方的內容將仍然可見,無論Alpha的值是多少。選中就是讓iOS明白不須要爲圖像視圖以後的東西浪費繪製時間。

如下是官方描述

default is YES. opaque views must fill their entire bounds or the results are undefined. the active CGContext in drawRect: will not have been cleared and may have non-zeroed pixels

8)分段加載數據

設置分頁加載數據,也就是上拉刷新和下拉加載。

如下是cell簡單複用代碼

#import "ViewController.h"
#import "XMGTestCell.h"

@interface ViewController ()

@end

@implementation ViewController

NSString *ID = @"wine";
- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.rowHeight = 100;

    // 註冊 ID這個標識 對應的 cell類型 爲UITableViewCell這種類型
    [self.tableView registerClass:[XMGTestCell class] forCellReuseIdentifier:ID];
}

#pragma mark - 數據源方法

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 200;
}

/**
 *  每當一個cell進入視野範圍內就會調用1次
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1.去緩存池取可循環利用的cell
    XMGTestCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    // 2.設置數據
    cell.textLabel.text = [NSString stringWithFormat:@"第%zd行數據",indexPath.row];
    return cell;

}
複製代碼
相關文章
相關標籤/搜索