在我的iPhone应用程序中,我正在使用iPhone的相机拍摄照片并将其保存到磁盘(应用程序的文档文件夹)。这是我如何保存它:
[UIImageJPEGRepresentation(photoTaken, 0.0) writeToFile:jpegPath atomically:YES];
使用最多压缩,我认为从磁盘读取图像会很快。但它不!我在我的一个视图中使用图像作为按钮的背景图像。我像这样加载它:
[self.frontButton setBackgroundImage:[UIImage imageWithContentsOfFile:frontPath] forState:UIControlStateNormal];
当我使用此按钮导航到视图时,它很慢且不连贯。我该如何解决这个问题?
答案 0 :(得分:39)
+imageWithContentsOfFile:
是同步的,因此主线程上的UI被磁盘操作中的图像加载阻塞并导致不稳定。解决方案是使用从磁盘异步加载文件的方法。您也可以在后台线程中执行此操作。这可以通过将+imageWithContentsOfFile:
包装在dispatch_async()
中,然后在包裹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
答案 1 :(得分:4)
这是我所知道的更快的方式。您需要导入#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
}
答案 2 :(得分:1)
我面临一个非常类似的问题,我必须从目录中加载数百个图像。如果我使用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) }
}
}