我需要从 NSDocumentDirectory 读取图像到多个 uiimageview 异步,这样它就不会阻塞 UI。我知道我可以在后台使用执行选择器来加载 uiimage,但是如何将它与动态 uiimageview 关联?
3 回答
一种方便的方法是使用块,例如:
[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+解码.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。
当您说“动态” 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!
如果您正在更新滚动视图,您可能需要检查该视图是否仍然可见,例如在这里或这里考虑。如果你正在更新一个表格视图,也许像这样检查单元格是否仍然可见。这一切都取决于你想要做什么。
您可以使用 NSThread/dispatch 队列来创建线程,这些线程可以创建您的 UIImageView-s 并在其中加载图像。