まいまいワークス

主にiPhoneアプリの開発で考えた事、調べた事、感じた事などを記していきます。

UITableView・UICollectionView攻略

iOSアプリの要となるtableviewとcollectionviewですが、設計の要点をおさえておかないとちょっとした事でスクロール時のパフォーマンスが落ちてしまい、アプリそのものの完成度の印象も格段に落ちてしまいます。 特にcollectionviewは1行に複数のアイテムが表示されるのでパフォーマンスがシビアになりがちです。

逆に、少しの心がけでスクロールにヌルヌル感が出てアプリのメジャー感も出るところなので設計には注意したいものです。
試行錯誤の末、かなりパフォーマンス改善が実感できるところまで来たので、
認識違いの点もあるかと思いますが留意点を列挙したいと思います。

   

注意すべき項目

  1. サーバーとの通信は非同期で行う
  2. collectionviewのcellForItemAtIndexPath、tableviewのcellForRowAtIndexPathの処理を高速にする
  3. layerによるシャドウ、角丸の効果は使わない
  4. 表示するUIImageViewのframeサイズとUIImageの画像サイズを合わせておく
  5. 透過画像、透過ビューを使わない

 

1.サーバーとの通信は非同期で行う

これは問題ないかと。 たまに初心者がハマる程度でしょうか。

 

2.collectionviewのcellForItemAtIndexPath、tableviewのcellForRowAtIndexPathの処理を高速にする

これらの処理はメインスレッドで行われるためここで時間がかかると処理がロックされてしまいます。
個人的な印象では0.01秒を越えると重たくなる印象があります。
複雑な処理はここでは行わずcellに値を渡すだけにするのが良さそうです。

//実験方法
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    
    NSLog(@"start");
    
    static NSString *cellID = @"testCell";
    _cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
    
【中略】
    //ここの処理が0.01秒を越えるとカクカク感が出てくる
    [NSThread sleepForTimeInterval:0.005];
【中略】    
    
    NSLog(@"end");

    return _cell;
}

 

3.layerによるシャドウ、角丸の効果は使わない

self.layer.cornerRadius = 10.f;
こんなやつです。
角丸もシャドウも数行のソース追加で見栄えのする効果が得られるのでついつい使いたくなりますが、(iPhone5sでも)目に見えて格段にパフォーマンスが落ちます。
別スレッドで画像そのものを加工するのが良さそうです

//UIImageを加工するクラスを別スレッドで叩く
-(void)round:(UIImage*)image{
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        __block UIImage *roundedImage = image;
        
        //ここでUIImageを加工するクラスを叩く
        roundedImage = [maskImageGenerate generateRoundedImage:image radius:10.f];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            //結果が返ってきたらmain_queueで値を返す(UIKitの決まり事)
            
            self.image = roundedImage;
            
        });
    });

}

 

4.表示するUIImageViewのframeサイズとUIImageの画像サイズを合わせておく

意外と盲点だったのがこれ。
例えば、サーバーから160x160pxで画像を取得して
pict.frame = CGRectMake(0, 0, 64, 64);

などとやってしまうとスクロールが重たくなってしまいます。
表示サイズの画像を取得するか(これがベスト)角丸処理と同様に別スレッドでUIImageの加工を行います。

    CGSize size = CGSizeMake(64.f, 64.f);
    UIGraphicsBeginImageContextWithOptions(size, NO, 2.0);
    [image drawInRect:CGRectMake(0, 0, 64.f, 64.f)];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

 

5.透過画像、透過ビューを使わない

一般論として透過画像は重いとよく言われていますが、今回試した中では一番差異を感じませんでした。
とは言え、多少なりともパフォーマンスに影響があると思われるので、背景色をベースカラーと合わせて透過画像を使わないようにしたり、drawRectで直接描画すればパフォーマンスが上がるようです。

 

大いに参考になったサイト

なめらかに動作するUITableViewのつくりかた
基本的なチューニングはこのサイトを参考にしました

[iOS] TableView スクロールパフォーマンスの改善
よりパフォーマンスを上げるためにはこちら