簡體   English   中英

在iPhone應用程序中從磁盤加載圖像很慢

[英]loading images from disk in iPhone app is slow

在我的iPhone應用程序中,我使用iPhone的相機拍攝照片並將其保存到磁盤(應用程序的文檔文件夾)。 這是我如何保存它:

[UIImageJPEGRepresentation(photoTaken, 0.0) writeToFile:jpegPath atomically:YES];

使用最多的壓縮,我認為從磁盤讀取圖像會很快。 但它不! 我在我的一個視圖中使用圖像作為按鈕的背景圖像。 我像這樣加載它:

[self.frontButton setBackgroundImage:[UIImage imageWithContentsOfFile:frontPath] forState:UIControlStateNormal];

當我使用此按鈕導航到視圖時,它很慢且不連貫。 我該如何解決?

+imageWithContentsOfFile:是同步的,因此主線程上的UI被磁盤操作中的圖像加載阻塞並導致不穩定。 解決方案是使用從磁盤異步加載文件的方法。 您也可以在后台線程中執行此操作。 這可以通過在dispatch_async()包裝+imageWithContentsOfFile:來輕松完成,然后在主要隊列上包裝-setBackgroundImage:的嵌套dispatch_async() -setBackgroundImage:因為UIKit方法需要在主線程上運行。 如果希望圖像在視圖加載后立即顯示,則需要從磁盤預先緩存圖像,以便在視圖出現時立即在內存中。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{

    UIImage *image = [UIImage imageWithContentsOfFile:frontPath];

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.frontButton setBackgroundImage:image forState:UIControlStateNormal];
    });

});

另外,如果按鈕圖像出現漸變,請考慮使用以下屬性來確保從磁盤加載的圖像文件很小:

- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets

或(不推薦使用,僅在您需要支持iOS 4.x時使用):

- (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight

這是我所知道的更快的方式。 您需要導入#import <ImageIO/ImageIO.h>

我使用此代碼在滾動期間,在滾動視圖內下載和壓縮圖像,您幾乎沒有注意到延遲。

CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)mutableData, NULL);
CFDictionaryRef options = (CFDictionaryRef)[[NSDictionary alloc] initWithObjectsAndKeys:(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform, (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent, (id)[NSNumber numberWithDouble:200.0], (id)kCGImageSourceThumbnailMaxPixelSize, nil];
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);

UIImage *image = [[UIImage alloc] initWithCGImage:thumbnail];
// Cache
NSString *fileName = @"fileName.jpg";
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"thumbnail"];
path = [path stringByAppendingPathComponent:fileName];
if ([UIImagePNGRepresentation(image) writeToFile:path atomically:YES]) {
    // Success
}

我面臨一個非常類似的問題,我必須從目錄中加載數百個圖像。 如果我使用UIImage(contentsOfFile :)方法,我的表現相當慢。 以下方法將我的表現提高到70%。

class ImageThumbnailGenerator:ThumbnailGenerator {private let url:URL

    init(url: URL) {
       self.url = url
    }

func generate(size: CGSize) -> UIImage? {
    guard let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil) else {
        return nil
    }

    let options: [NSString: Any] = [
        kCGImageSourceThumbnailMaxPixelSize: Double(max(size.width, size.height) * UIScreen.main.scale),
        kCGImageSourceCreateThumbnailFromImageIfAbsent: true
    ]

    return CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as NSDictionary).flatMap { UIImage(cgImage: $0) }
 }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM