【问题标题】:images from documents asynchronous来自文档异步的图像
【发布时间】:2014-05-13 19:48:42
【问题描述】:

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

【问题讨论】:

    标签: iphone ios


    【解决方案1】:

    一种方便的方法是使用块,例如:

    [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

    【讨论】:

    • 很棒的答案。谢谢!
    • 这是一个很好的答案。我们可以修改它以添加取消机制
    【解决方案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。如果您正在更新一个表格视图,也许像this 这样会检查单元格是否仍然可见。这完全取决于您要做什么。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2015-01-07
        • 2015-08-08
        • 1970-01-01
        • 1970-01-01
        • 2019-02-20
        • 2013-02-19
        • 2011-05-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多