【问题标题】:Loading UIImage in background thread causes ImageIO error在后台线程中加载 UIImage 会导致 ImageIO 错误
【发布时间】:2012-02-16 00:11:56
【问题描述】:

我正在开发一个 iOS 项目,该项目从后台线程中的 URL 加载 UIImage,并将它们显示在水平分页的滚动视图中。此行为应模仿 iPhone 的本机照片库应用程序的行为。我以我认为应该工作的方式进行了所有设置,但是在主 UI 图形上下文中绘制 UIImages 时,我偶尔会在控制台中看到此消息打印出来:

ImageIO: <ERROR>  CGImageReadSessionGetCachedImageBlockData *** CGImageReadSessionGetCachedImageBlockData: bad readSession [0x685e590]

尽管出现此错误,但应用程序似乎运行良好,并且图像按预期绘制。我应该简单地忽略这个“错误”,还是应该改变我在后台线程中加载图像的方法?目前,我使用 UIImage initWithData: 方法在后台线程中加载图像:

- (void)backgroundLoadThread:(NSURL *)url {
    @autoreleasepool {
        NSData * imageData = [NSData dataWithContentsOfURL:url];
        UIImage * theImage = [[UIImage alloc] initWithData:imageData];
        if ([[NSThread currentThread] isCancelled]) {
#if !__has_feature(objc_arc)
            [theImage release];
#endif
            return;
        }
        [self performSelectorOnMainThread:@selector(loadComplete:)
                               withObject:theImage waitUntilDone:NO];
    }
}

我的loadComplete: 方法只是保留作为实例变量传递的图像,稍后在视图的drawRect: 方法中绘制。在drawRect: 中,我使用的是 UIImage drawInRect: 方法,这似乎是控制台中错误消息的肇事者。但是,使用 CGContextDrawImage 绘制图像的底层 CGImageRef 仍然会导致相同的错误。完整的源代码可以在这个项目的 Github 存储库中找到,在文件 ANAsyncImageView.m 中。

编辑:我现在更改了后台线程以从文件加载 CGImage,然后回调到主线程,使用免费桥接传递 CGImageRef。不幸的是,这仍然会产生同样的问题,向我证明 UIImage 的imageWithCGImage: 必须以某种方式保留对原始 CGImage 的引用。查看上面链接的文件中的代码(到 Github 存储库)以获取完整代码:

NSData * imageData = [NSData dataWithContentsOfURL:url];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)imageData);
CGImageRef loaded = CGImageCreateWithPNGDataProvider(provider, NULL, false, kCGRenderingIntentDefault);
CGDataProviderRelease(provider);

id imageObj = (id)loaded;        
[self performSelectorOnMainThread:@selector(loadComplete:) withObject:imageObj waitUntilDone:NO];
CGImageRelease(loaded);

【问题讨论】:

  • 无论线程是否已取消,您不应该发布该图像吗? performSelectorOnMainThread:withObject:waitUntilDone: 将为您保留和释放该对象,因此您不必担心它会从您身下消失。
  • 请先看这个答案:stackoverflow.com/a/26562349/1084174

标签: ios cocoa-touch uikit uiimage core-graphics


【解决方案1】:

UIKit 不是线程安全的类。因此,您不应该从后台调用 UIImage。

与其创建 UIImages,不如将图像文件渲染成 CGImageRefs。您可以将其中之一传回主线程并从中生成 UIImage(您仍然可以通过将繁重的图像解压工作移至后台来受益)。

【讨论】:

  • 我对其进行了更改,以便后台线程现在加载一个 CGImageRef,并将其传递给主线程,然后使用imageWithCGImage: 从它创建一个 UIImage。控制台中仍会打印出相同的消息。
  • 既然如此,这个答案根本不能解决问题。
  • 您是在设备上运行还是在模拟器中运行?无论如何,你会得到同样的错误吗?
  • 我在模拟器上得到错误。截至目前,我没有可用于测试的设备。正如我所提到的,该错误似乎无论如何都不是致命的,它可能只是 ImageIO 的一个内部问题,我不应该担心。这将很难确定,除非我在设备上测试应用程序,或者找出解决办法。
  • 您共享的代码中似乎没有“错误”(除了在后台最初使用 UIKit,您已更正)。该错误也可能是特定于模拟器的(我遇到了仅在模拟器中发生的图像 IO 问题)...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多