我需要将NSDocumentDirectory中的图像读取到多个uiimageview异步,因此它不会阻止UI。 我知道我可以在后台使用执行选择器来加载uiimage,但是我如何将它与动态uiimageview相关联?
答案 0 :(得分:4)
一种方便的方法是使用块,例如:
[self loadFullImageAt:imagePath completion:^(UIIMage * image){
self.imageView.image = image;
}];
将图像作为数据加载的位置(因为UIImage
否则会加载延迟的图像数据 - 首次访问时)。在仍然在后台线程中解压缩图像也是一个好主意,因此当我们第一次使用图像时,主线程不必这样做。
- (void)loadFullImageAt:(NSString *)imageFilePath completion:(MBLoaderCompletion)completion {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSData *imageData = [NSData dataWithContentsOfFile:imageFilePath];
UIImage *image = nil;
if (imageData) {
image = [[[UIImage alloc] initWithData:imageData] decodedImage];
}
dispatch_async(dispatch_get_main_queue(), ^{
completion(image);
});
});
}
回调定义为:
typedef void (^MBLoaderCompletion)(UIImage *image);
这是实现解压缩代码的UIImage
类别:
<强>的UIImage + Decode.h 强>
#import <UIKit/UIKit.h>
@interface UIImage (Decode)
- (UIImage *)decodedImage;
@end
<强>的UIImage + Decode.m 强>
#import "UIImage+Decode.h"
@implementation UIImage (Decode)
- (UIImage *)decodedImage {
CGImageRef imageRef = self.CGImage;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL,
CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef),
8,
// Just always return width * 4 will be enough
CGImageGetWidth(imageRef) * 4,
// System only supports RGB, set explicitly
colorSpace,
// 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 scale:self.scale orientation:self.imageOrientation];
CGImageRelease(decompressedImageRef);
return decompressedImage;
}
@end
此处提供的示例代码假定我们使用 ARC 。
答案 1 :(得分:2)
当你说“动态”UIImageView时,这些是在UIScrollView上以编程方式创建的吗?在UITableView上? samfisher在基本问题上是完全正确的,但细节根据您创建UIImageView的方式而有所不同(例如,如果UITableView,您需要确保单元格仍然可见且尚未出列;如果是UIScrollView,即使这样如果图像在屏幕上仍然可见(特别是如果图像很大或很多),你可能只想加载UIImageView。)
但基本的想法是你可以做类似的事情:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *image = [self getTheImage];
// ok, now that you have the image, dispatch the update of the UI back to the main queue
dispatch_async(dispatch_get_main_queue(), ^{
// if the image view is still visible, update it
});
});
请注意,您在某个后台队列或线程上调用图像检索,但请确保在主线程上更新UI!
如果您要更新滚动视图,则可能需要检查视图是否仍然可见,例如预期here或here。如果您正在更新tableview,可能会像this那样检查单元格是否仍然可见。这一切都取决于你想要做什么。
答案 2 :(得分:1)
您可以使用NSThread / dispatch队列来创建可以创建UIImageView-s并在其中加载图像的线程。