我正在开发一个iOS项目,该项目从后台线程中的URL加载UIImages,并在水平分页滚动视图中显示它们。此行为应该模仿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文件中找到。
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);
答案 0 :(得分:6)
UIKit不是一个线程安全的类。因此,您不应该从后台调用UIImage。
不是创建UIImages,而是将图像文件渲染为CGImageRefs。您可以将其中一个传递回主线程并从中生成UIImage(您仍然可以通过将图像解压缩的重复移动到背景中而获益。)