Okogeki'sブログ

デキるエンジニアを目指すOkogekiのブログ

UIScrollViewでの画像表示高速化、最適化についてのtipsその1

60FPS維持しつつ画像描写がめちゃムズい

UIScrollViewは60FPSで動いてるとの事で、
これを維持しつつ、
画像をなめらかにするのは難しい。工夫が必要。
色んな記事でこの問題は良く目にします。

解決策に「imageNamedを使おう」を良くみるが。。。

[UIImage imageNamed:XXX]は画像キャッシュし、読み込みが早い、
[UIImage imageWithContentsOfFile:XXX]は画像キャッシュせず、読み込みが遅い
ってなわけで「imageNamedを使おう!」
で終わっている記事が多いのですが、
imageNamedでもスクロール中に表示すると、
初回読み込み時につっかかる感触がある。
(私の意見としては後述の画像展開が悪さしているのであって、これは本質じゃないと思ってますが、深追いは止めときます)

圧縮形式画像→展開が重い

初回読み込み時だけってなんでかなー・・・。と模索してたところ、
どうやら「圧縮画像ファイル→展開」処理に
すごい時間かかってるらしい事が分かった。

展開を自前でやってみる

ViewDidLoadの段階で無圧縮展開してしまえば、
快適なスクロールビューが実装できるのではと思いたち、
サンプルコードを書いてみる事に。

nonCompressImageメソッドをViewDidロードで呼び、
圧縮画像ファイル→展開を自分でやってます。

自分で展開せずに、UIImageViewに展開を任せた場合の
つっかかりを確認する場合は、コメントアウトしている部分を
入れ替えてみてください。

つっかからなくなった!

つっかかりが一切消えました。やった。
後はメモリへの負担を気にしながらNSCacheなりで
画像のキャッシュ化をしてあげれば
imageWithContentsOfFileのパターンでの
高速表示もできますね。
これもかなり需要ありそうなのでtipsその2でのネタにしたいと思います。

今回は割と自分の勉強にもなりました。ScrollView最適化に
詳しくなっておくと、色々重宝されそうなのでもっと勉強します。


#import "ViewController.h"

@interface ViewController (){
    
    UIImageView* imageView;
    UIImage* image;

}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIScrollView *sv = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    UIView *uv = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height*5)];
    imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, self.view.frame.size.height*2, self.view.frame.size.width,self.view.frame.size.height)];
    [uv addSubview:imageView];
    
    [sv addSubview:uv];
    sv.contentSize = uv.bounds.size;
    sv.delegate = self;
    [self.view addSubview:sv];
    
    image = nonCompressImage([UIImage imageNamed:@"sample.png"]);
    
}

-(void)scrollViewDidScroll:
(UIScrollView *)scrollView{
    
    int page = scrollView.contentOffset.y / scrollView.frame.size.height;
    
    if(page==2){
        
        //こっちのほうに変えるとつっかかる。
        //imageView.image = [UIImage imageNamed:@"sample.png"];
        
        
        //こっちに変えるとつっかからない
        imageView.image = image;
    
    }

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

static UIImage * nonCompressImage(UIImage *image) {
    
    UIGraphicsBeginImageContext(CGSizeMake(image.size.width, image.size.height));
    [image drawAtPoint:CGPointMake(0,0)];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return image;
    
}

@end