来自文档异步的图像

时间:2012-08-23 16:36:53

标签: iphone ios

我需要将NSDocumentDirectory中的图像读取到多个uiimageview异步,因此它不会阻止UI。 我知道我可以在后台使用执行选择器来加载uiimage,但是我如何将它与动态uiimageview相关联?

3 个答案:

答案 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!

如果您要更新滚动视图,则可能需要检查视图是否仍然可见,例如预期herehere。如果您正在更新tableview,可能会像this那样检查单元格是否仍然可见。这一切都取决于你想要做什么。

答案 2 :(得分:1)

您可以使用NSThread / dispatch队列来创建可以创建UIImageView-s并在其中加载图像的线程。