【发布时间】: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:将为您保留和释放该对象,因此您不必担心它会从您身下消失。
标签: ios cocoa-touch uikit uiimage core-graphics