23

私が抱えている問題と、それをどのように解決しようとしたかについてお話ししましょう。左から右にスクロールするときにサブビューをロードする UIScrollView があります。各サブビューには、それぞれ約 400x200 の 10 ~ 20 個の画像があります。ビューからビューへとスクロールすると、かなりの遅延が発生します。

調査した結果、すべてのビューをアンロードして再試行したところ、遅延が解消されたことがわかりました。画像の同期キャッシュが遅延の原因であると考えました。そこで、画像を非同期でロードする UIImageView のサブクラスを作成しました。読み込みコードは次のようになります (self.dispatchQueueシリアル ディスパッチ キューを返します)。

- (void)loadImageNamed:(NSString *)name {
    dispatch_async(self.dispatchQueue, ^{
        UIImage *image = [UIImage imageNamed:name];

        dispatch_sync(dispatch_get_main_queue(), ^{
            self.image = image;
        });
    });
}

ただし、すべての UIImageViews をこのサブクラスに変更した後でも、ラグが発生しました (軽減されたかどうかはわかりません)。問題の原因を に煮詰めましたself.image = image;。なぜこれが非常に多くの遅延を引き起こしているのですか (ただし、最初のロード時のみ)?

私を助けてください。=(

4

2 に答える 2

55

編集 3: iOS 15 が提供されるようになりUIImage.prepareForDisplay(completionHandler:)ました。

image.prepareForDisplay { decodedImage in
    imageView.image = decodedImage
}

また

imageView.image = await image.byPreparingForDisplay()

編集 2: これは、いくつかの改善を含む Swift バージョンです。(未テスト) https://gist.github.com/fumoboy007/d869e66ad0466a9c246d


編集:実際、必要なのは次のことだけだと思います。(未テスト)

- (void)loadImageNamed:(NSString *)name {
    dispatch_async(self.dispatchQueue, ^{
        // Determine path to image depending on scale of device's screen,
        // fallback to 1x if 2x is not available
        NSString *pathTo1xImage = [[NSBundle mainBundle] pathForResource:name ofType:@"png"];
        NSString *pathTo2xImage = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"png"];

        NSString *pathToImage = ([UIScreen mainScreen].scale == 1 || !pathTo2xImage) ? pathTo1xImage : pathTo2xImage;


        UIImage *image = [[UIImage alloc] initWithContentsOfFile:pathToImage];

        // Decompress image
        if (image) {
            UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);

            [image drawAtPoint:CGPointZero];

            image = UIGraphicsGetImageFromCurrentImageContext();

            UIGraphicsEndImageContext();
        }


        // Configure the UI with pre-decompressed UIImage
        dispatch_async(dispatch_get_main_queue(), ^{
            self.image = image;
        });
    });
}

self.image = image;元の回答:直接ではなかったことが判明しました。UIImage 画像読み込みメソッドは、画像データをすぐに解凍および処理しません。ビューがその表示を更新するときにそれを行います。そこで解決策は、Core Graphics のレベルを下げて、自分で画像データを解凍して処理することでした。新しいコードは次のようになります。

- (void)loadImageNamed:(NSString *)name {
    dispatch_async(self.dispatchQueue, ^{
        // Determine path to image depending on scale of device's screen,
        // fallback to 1x if 2x is not available
        NSString *pathTo1xImage = [[NSBundle mainBundle] pathForResource:name ofType:@"png"];
        NSString *pathTo2xImage = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"png"];
        
        NSString *pathToImage = ([UIScreen mainScreen].scale == 1 || !pathTo2xImage) ? pathTo1xImage : pathTo2xImage;
        
        
        UIImage *uiImage = nil;
        
        if (pathToImage) {
            // Load the image
            CGDataProviderRef imageDataProvider = CGDataProviderCreateWithFilename([pathToImage fileSystemRepresentation]);
            CGImageRef image = CGImageCreateWithPNGDataProvider(imageDataProvider, NULL, NO, kCGRenderingIntentDefault);
            
            
            // Create a bitmap context from the image's specifications
            // (Note: We need to specify kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
            // because PNGs are optimized by Xcode this way.)
            CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
            CGContextRef bitmapContext = CGBitmapContextCreate(NULL, CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerComponent(image), CGImageGetWidth(image) * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
            
            
            // Draw the image into the bitmap context
            CGContextDrawImage(bitmapContext, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
            
            //  Extract the decompressed image
            CGImageRef decompressedImage = CGBitmapContextCreateImage(bitmapContext);
            
            
            // Create a UIImage
            uiImage = [[UIImage alloc] initWithCGImage:decompressedImage];
            
            
            // Release everything
            CGImageRelease(decompressedImage);
            CGContextRelease(bitmapContext);
            CGColorSpaceRelease(colorSpace);
            CGImageRelease(image);
            CGDataProviderRelease(imageDataProvider);
        }
        
        
        // Configure the UI with pre-decompressed UIImage
        dispatch_async(dispatch_get_main_queue(), ^{
            self.image = uiImage;
        });
    });
}
于 2012-05-30T15:00:36.527 に答える
0

問題は画像自体にあると思います。たとえば、私のプロジェクトの 1 つで、互いにアルファ透明度でレイヤー化された 640x600 の 10 枚の画像を取得しました。このviewcontrollerからviewcontrollerをプッシュまたはポップしようとすると、かなり遅れます。

少数の画像のみを残すか、非常に小さい画像を使用する場合-遅延はありません。

PSはsdk 4.2 ios5 iphone 4でテスト済み。

于 2012-05-28T20:51:27.047 に答える