iOS開發筆記之TableView優化


 

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

既然用的這么頻繁,肯定就會在開發過程中碰到一些問題--比如屏幕掉幀、卡頓等現象。這些現象大幅度的降低了用戶的性能體驗,並提高了crash的頻率。

因此如何能優化好tableView就非常考驗程序猿們的功底了。

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

首先當一個tableView需要顯示內容的時候,首先會發送網絡請求,向服務器請求數據,然后將數據轉為我們可以使用的model后進行reload操作,接下來會向delegate和

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

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

這個代理方法的實現,在可見的頁面是會重復繪制頁面的,所以絕大部分人都會在這里做一些代碼處理
比如:

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;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM