2013-10-30 4 views
8

私のアプリでは、大きなJPEG画像を読み込んでスクロール表示する必要があります。 UIの応答性を保つために、イメージをバックグラウンドでロードしてメインスレッドに表示することにしました。私はバックグラウンドでそれらを完全にロードするために、各イメージを強制的に圧縮解除します。私は、画像を解凍するためにこのコードを使用してだった(私のアプリは、iOSの7のみであることに注意してくださいので、私はバックグラウンドスレッドでこれらのメソッドを使用してOKであることを理解して):なぜこのコードはUIImageを純粋なアプローチよりもはるかに優れたものにするのでしょうか?

+ (UIImage *)decompressedImageFromImage:(UIImage *)image { 
    UIGraphicsBeginImageContextWithOptions(image.size, YES, 0); 
    [image drawAtPoint:CGPointZero]; 
    UIImage *decompressedImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return decompressedImage; 
} 

をしかし、私はまだ長い負荷を持っていました時間、UIの吃音、および大量のメモリ圧迫があります。私はちょうど見つけたanother solution

+ (UIImage *)decodedImageWithImage:(UIImage *)image { 
    CGImageRef imageRef = image.CGImage; 
    // System only supports RGB, set explicitly and prevent context error 
    // if the downloaded image is not the supported format 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    CGContextRef context = CGBitmapContextCreate(NULL, 
               CGImageGetWidth(imageRef), 
               CGImageGetHeight(imageRef), 
               8, 
               // width * 4 will be enough because are in ARGB format, don't read from the image 
               CGImageGetWidth(imageRef) * 4, 
               colorSpace, 
               // kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little 
               // makes system don't need to do extra conversion when displayed. 
               kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little); 
    CGColorSpaceRelease(colorSpace); 

    if (! context) { 
     return nil; 
    } 
    CGRect rect = (CGRect){CGPointZero, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)}; 
    CGContextDrawImage(context, rect, imageRef); 
    CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context); 
    CGContextRelease(context); 
    UIImage *decompressedImage = [[UIImage alloc] initWithCGImage:decompressedImageRef]; 
    CGImageRelease(decompressedImageRef); 
    return decompressedImage; 
} 

このコードは大きかった。画像はほとんど直ちに読み込まれ、UIスタッターはなく、メモリー使用量は下がっています。

だから私の質問は二つある:

  1. なぜ第二の方法は、最初よりもそんなに良いですか?
  2. デバイスの固有のパラメータのために2番目の方法が優れている場合は、現在および将来のすべてのiOSデバイスで同様にうまく機能するようにする方法がありますか?私は、この問題を再現して、私の上で変化するネイティブのビットマップ形式を想定したくありません。

答えて

6

これはRetinaデバイスで実行しているものとします。 UIGraphicsBeginImageContextWithOptionsでは、メインスクリーンの縮尺であるデフォルト縮尺2を要求しました。これは、4倍の大きさのビットマップを生成していることを意味します。 2番目の関数では、1倍の縮尺で描画しています。

1の縮尺をUIGraphicsBeginImageContextWithOptionsにして、あなたのパフォーマンスが似ているかどうかを確認してください。

+0

ブリリアント。はい、私は網膜のデバイスで実行しています。はい、スケール= 1を設定すると、私には同様のパフォーマンスとメモリ使用量が与えられます。最初の方法は、デバイスの特性が何であれ、正しいことを期待しているので、今すぐ行ってみましょう。 –

+0

両方の世界(スピードと美しさ、より多くのコードを犠牲にして)を最大限に活用するには、クイック1倍レンダリング(または0.5倍レンダリング)を表示してから、後で網膜レンダリングを実行する画像はまだ画面上に表示されます。例については、https://github.com/iosptl/ios6ptl/tree/master/ch13/JuliaOpを参照してください(これはiOS 6プログラミングの第13章の制限事項を踏襲しています;それはiOS 7 PTLの第9章です今年の後半に出ます) –

+0

UIGraphicsBeginImageContextWithOptionsをscale = 1に変更すると、アップスケーリング時に画像の品質が非常に悪くなります。 CGImageを使用しているコードは、強制伸張が使用されていないときと同じように高品質でレンダリングされます。 また、UIGraphicsBeginImageContextWithOptionsが不透明に指定されていて、透明では機能しません –

関連する問題