2011-11-04 123 views
8

在我的iPhone应用程序中,我使用iPhone的相机拍摄照片并将其保存在磁盘(应用程序的文档文件夹)中。这是我如何保存:在iPhone应用程序中从磁盘加载图像很慢

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

使用最压缩,我想从磁盘读取图像的速度可能很快。但它不是!我在一个视图中将图像用作按钮的背景图像。我加载它是这样的:

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

当我导航到与该按钮的视图,它是缓慢和不连贯。我该如何解决?

回答

37

+imageWithContentsOfFile:是同步的,所以您的主线程上的UI被从磁盘操作加载的映像阻塞并导致不连续。解决方案是使用从磁盘异步加载文件的方法。你也可以在后台线程中做到这一点。这可以通过将+imageWithContentsOfFile:包装在dispatch_async()中,然后在主队列上嵌套dispatch_async()来实现,因为UIKit方法需要在主线程上运行,所以在主队列上包装-setBackgroundImage:。如果您希望图像在视图加载后立即出现,您需要预先从磁盘缓存图像,以便在视图出现时立即将其存储在内存中。

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 
+0

你救我一命!谢谢! –

+0

@Andrew你如何预缓存? re:“你需要预先从磁盘缓存图像” –

+0

@Van Du Tran,在这种情况下预缓存意味着在你需要之前(例如在视图出现之前)将图像加载到UIImage中。这样,当您加载视图时,图像已经保存在内存中,因此无需磁盘I/O即可将其显示在屏幕上。 – Andrew

2

这是我知道的更快的方式。您需要导入#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 
} 
+0

如果此代码对您而言仍然很慢,您只需将其放入一个线程中即可。请注意,“200。0“是你想要的像素的最大尺寸。 –

0

我面对一个非常类似的问题,我不得不从目录中加载数百个图像。如果我使用UIImage(contentsOfFile :)方法,我的表现很慢。以下方法将我的表现提高到70%。

类ImageThumbnailGenerator:ThumbnailGenerator { 私人让利网址:网址

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) } 
} 
} 
相关问题