2

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

4

3 回答 3

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+解码.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

于 2012-08-23T16:56:32.360 回答
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!

如果您正在更新滚动视图,您可能需要检查该视图是否仍然可见,例如在这里这里考虑。如果你正在更新一个表格视图,也许像这样检查单元格是否仍然可见。这一切都取决于你想要做什么。

于 2012-08-23T16:52:15.160 回答
1

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

于 2012-08-23T16:40:43.043 回答