[更新:此问题已解决;这个问题不在drawInRect:
,但在UIGraphicsBeginImageContext()
]必须drawInRect:在主线程上执行一个单独的上下文吗?
在我的应用程序,我抓住一堆大图像,剪裁缩略图大小和存储缩略图预览。
请注意,我在单独的图像上下文中执行此操作 - 这是而不是有关重新绘制屏幕上的UIView
。
此代码相当密集,所以我在单独的线程中运行它。实际的比例是这样的,而且是对UIImage
顶部的类别执行:
- (UIImage *) scaledImageWithWidth:(CGFloat)width andHeight:(CGFloat)height
{
CGRect rect = CGRectMake(0.0, 0.0, width, height);
UIGraphicsBeginImageContext(rect.size);
[self drawInRect:rect]; // <-- crashing on this line
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
这是从一个单独的方法,它通过将图像中的循环转,做了处理调用。上述方法的实际调用看起来是这样的:
UIImage *small = [bigger scaledImageWithWidth:24.f andHeight:32.f];
这一切工作的大部分时间,但偶尔我得到一个EXC_BAD_ACCESS
。
回溯:
#0 0x330d678c in ripc_RenderImage()
#1 0x330dd5aa in ripc_DrawImage()
#2 0x300e3276 in CGContextDelegateDrawImage()
#3 0x300e321a in CGContextDrawImage()
#4 0x315164c8 in -[UIImage drawInRect:blendMode:alpha:]()
#5 0x31516098 in -[UIImage drawInRect:]()
#6 0x0000d6e4 in -[UIImage(Scaling) scaledImageWithWidth:andHeight:] (self=0x169320, _cmd=0x30e6e, width=48, height=64) at /Users/me/Documents/svn/app/trunk/Classes/UIImage+Scaling.m:20
#7 0x00027df0 in -[mgMinimap loadThumbnails] (self=0x13df00, _cmd=0x30d05) at /Users/me/Documents/svn/app/trunk/Classes/mgMinimap.m:167
#8 0x32b15bd0 in -[NSThread main]()
#9 0x32b81cfe in __NSThread__main__()
#10 0x30c8f78c in _pthread_start()
#11 0x30c85078 in thread_start()
[更新4]当我在模拟器中运行这个,还有这个问题发生,控制台还显示以下内容:
// the below is before loading the first thumbnail
<Error>: CGContextSaveGState: invalid context
<Error>: CGContextSetBlendMode: invalid context
<Error>: CGContextSetAlpha: invalid context
<Error>: CGContextTranslateCTM: invalid context
<Error>: CGContextScaleCTM: invalid context
<Error>: CGContextDrawImage: invalid context
<Error>: CGContextRestoreGState: invalid context
<Error>: CGBitmapContextCreateImage: invalid context
// here, the first thumbnail has finished loading and the second one
// is about to be generated
<Error>: CGContextSetStrokeColorWithColor: invalid context
<Error>: CGContextSetFillColorWithColor: invalid context
我的直觉是,我偶尔最终会尝试drawInRect:
,而操作系统也在尝试绘制某些东西,偶尔会导致崩溃。我总是推测,只要你不画实际的屏幕,这是可以接受的 - 是不是这种情况?或者如果是这样的话,有什么想法可能会造成这种情况?
更新(r2):我忘了提及这个应用程序运行在相当严重的内存限制下(我有很多图像在任何给定的时间加载,这些交换进/出),所以这可能是内存不足的情况(继续阅读 - 不是)。但我不确定如何验证,所以对此的想法也会受到欢迎。我通过严格减少正在加载的图像数量并添加一个检查以确保它们正确地释放(它们是,并且崩溃仍然发生)来验证这一点。
更新3:我以为我发现了这个问题。下面是我写的答案,在崩溃再次发生之前:
代码会(在我发布此问题后)偶尔以退出代码0
开始退出,有时退出代码为10 (SIGBUS)
。 0
意味着“没有错误”,所以这是非常奇怪的。 10
似乎意味着一切,所以这也无济于事。但是,当碰撞发生在那里时,电话drawInRect:
是一个很大的暗示。
通过循环显示缩略图,生成了许多自动发布的图像。我有一个autorelease池,但它包装整个for循环。我添加了第二个自动释放池for
循环中:
- (void)loadThumbnails
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (...) {
NSAutoreleasePool *cyclePool =
[[NSAutoreleasePool alloc] init]; // <-- here
UIImage *bigger = ...;
UIImage *small = [bigger scaledImageWithWidth:24.f andHeight:32.f];
UIImage *bloated = [i scaledImageWithWidth:48.f andHeight:64.f];
[cyclePool release]; // <-- ending here
}
[pool release];
}
我想上面的固定问题,直到我跑的应用程序,它与“退出代码0”又不仅限于之前坠毁,机上我。回到绘图板...
从iOS4.0开始绘制到UIKit中的图形上下文现在是线程安全的。具体来说: 用于访问和操作图形上下文的例程现在可以正确处理驻留在不同线程上的上下文。参考:http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html#//apple_ref/doc/uid/TP40009559-SW29 – MattyG 2011-09-14 04:03:44
感谢您的发现,MattyG。绝对有趣。 – Kalle 2011-10-03 16:10:56
@Kalle:你改变了什么代码?你可以分享吗? – 2014-10-02 09:52:58