iOS開發筆記之TableView優化

 

TableView相信只要是作iOS開發的就不會陌生,目前大多數iOS的app都是採用TabBar+NavigationBar+TableViewController這一主流框架,android

既然用的這麼頻繁,確定就會在開發過程當中碰到一些問題--好比屏幕掉幀、卡頓等現象。這些現象大幅度的下降了用戶的性能體驗,並提升了crash的頻率。程序員

所以如何能優化好tableView就很是考驗程序猿們的功底了。性能優化

本猿~啊呸,只要開發公司項目的時候就會遇到這類問題,當快速滑動tableView而且cell中有大量圖片和其餘控件須要加載時,就會出現嚴重掉幀(通常公司的項目當時大量採用xib如今逐漸用手寫代碼代替),有時還會crash。因爲當時項目比較趕進度,因此沒有時間去優化性能,這種狀況直到功能基本完善爲止,花了大量功夫進行性能優化。
接下來我會根據tableView的delegate以及dataSource方法的執行順序進行一步一步的講解。服務器

首先當一個tableView須要顯示內容的時候,首先會發送網絡請求,向服務器請求數據,而後將數據轉爲咱們可使用的model後進行reload操做,接下來會向delegate和網絡

dataSource請求數據。這時候會先調用- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 這個方法(假設section爲1)。根據app

model獲取cell的行數而後調用-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath,根據model計算出cell的高度。因爲框架

tableView是繼承自scrollView,因此tableView也會有contentSize屬性。它的contentSize取決於全部cell的高度和。和scrollView有一點不一樣,tableView只會管理可視的cell高度,這樣作的目的是避免沒必要要的性能開銷。異步

 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

這個代理方法的實現,在可見的頁面是會重複繪製頁面的,因此絕大部分人都會在這裏作一些代碼處理
好比:oop

static NSString *CellIdentifier = @"LazyTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

  很常規的,防止cell對象無限的被建立,等同於android裏面適配器的方法性能

以上舉例代碼是可讓cell被重複使用,通常大概只會在可見頁面部分的幾個cell會被建立下,其餘的所有重複使用前面已經有的cell對象,到時候只要填充數據就能夠了

那麼僅僅只是如此,恐怕如今的cell自定義的頁面不僅是文本那麼簡單,多多少少都會帶有一些圖片吧,當你下滑時候是否發現有那麼一點點的卡頓現成,特別是網絡很差,並且仍是在iPhone4上跑的就會更明顯了

那麼在cell裏面異步加載圖片是個程序員都會想到,可是若是你給每一個循環對象都加上異步加載,而且下滑的時候,這一操做將會被執行,雖然是異步,可是一個app裏面的線程過多也會卡頓的,特別是在下滑操做的時候給每一個圖片進行異步加載。

那麼這裏能夠利用UIScrollViewDelegate代理很好的解決這問題:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

能夠識別tableview禁止或者減速滑動結束的時候進行異步加載圖片。

如下方法來執行異步加載操做:

 //獲取可見部分的對象
       NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows];
        for (NSIndexPath *indexPath in visiblePaths)
        {
           //獲取的dataSource裏面的對象,而且判斷加載完成的不須要再次異步加載
             <code>
        }

同時在cell繪製中也作限制

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

         if (self.tableView.dragging == NO && self.tableView.decelerating == NO)
            {
               //開始異步加載圖片
                <code>
            }

tableview 中止滑動的時候開始異步加載圖片

最後也別忘記在內存緊張的狀況下釋放調全部的異步線程,以保證的你的app不會被系統強制關閉

- (void)didReceiveMemoryWarning{
//  釋放調異步加載圖片的線程以及全部圖片資源對象
<code>
}

還有千萬別忘記銷燬的時候手動把全部的使用到的代理設置nil。

 

還有一個利用線程和Runloop延遲加載圖片的新思路:

[self.avatarImageView performSelector:@selector(serImage:)    
                        withObjetc:downloadedImage
                        afterDelay:0
                        inModes:@[NSDefaultRunLoopMode]]
 + (NSThread *)networkRequestThread {
      static NSThread *_networkRequestThread = nil;
      static dispatch_once_t oncePredicate;
      dispatch_once(&oncePredicate, ^{
      _networkRequestThread =
      [[NSThread alloc] initWithTarget:self
           selector:@selector(networkRequestThreadEntryPoint:)
           object:nil];
      [_networkRequestThread start];
 });

 return _networkRequestThread;
相關文章
相關標籤/搜索