必须drawInRect:在主线程上执行单独的上下文? [英] Must drawInRect: for a separate context be executed on the main thread?

查看:156
本文介绍了必须drawInRect:在主线程上执行单独的上下文?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[更新:此问题已解决;问题不在 drawInRect:但在 UIGraphicsBeginImageContext()]

[update: this problem has been resolved; the issue was not in drawInRect: but in UIGraphicsBeginImageContext()]

在我的应用程序中,我正在抓取一堆大图像,将它们裁剪为缩略图大小并存储缩略图以进行预览。

In my app, I'm grabbing a bunch of large images, cropping them down to thumbnail size and storing the thumbnails for previewing.

请注意,我是在一个单独的图像上下文中执行此操作 - 这是关于重新绘制 UIView 在屏幕上。

Note that I'm doing this in a separate image context -- this is not about redrawing a UIView that is on the screen.

这段代码相当密集,所以我在一个单独的线程中运行它。实际缩放看起来像这样,并且是 UIImage 之上的类别实现:

This code is rather intensive so I'm running it in a separate thread. The actual scaling looks like this, and is a category implementation on top of 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;
}

这是从一个单独的方法调用的,它依次遍历图像并且做处理。对上述方法的实际调用如下所示:

This is called from a separate method, which loops through the images in turn and does the processing. The actual call to the above method looks like this:

UIImage *small = [bigger scaledImageWithWidth:24.f andHeight:32.f];

这一切都在大部分时间都有效,但偶尔我会得到 EXC_BAD_ACCESS

This all works most of the time, but occasionally I get an EXC_BAD_ACCESS.

Backtrace:

Backtrace:

#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]当我在模拟器中运行时,出现此问题时,控制台还会显示以下内容:

[update 4] When I run this in the Simulator, and this problem happens, the console additionally shows the following:

// 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:而操作系统也试图绘制一些东西,偶尔会导致崩溃。我总是假设只要你不在实际屏幕上画画,这是可以接受的 - 这不是这种情况吗?或者如果是这种情况,任何想法可能导致这种情况?

My gut feeling is that I occasionally end up trying to drawInRect: while the OS is also trying to draw something, which results, occasionally, in a crash. I always presumed that as long as you don't draw on the actual screen, this is acceptable -- is this not the case? Or if it is the case, any idea what might be causing this?

更新(r2):我忘了提到这个应用程序在相当严重的内存限制下运行(我在任何给定的时间都加载了很多图像并且这些图像被交换进/出),所以这可能是内存不足的情况(继续阅读 - 它不是)。我不知道如何验证这一点,所以对此的想法也会受到欢迎。我通过严格减少正在加载的图像数量并添加一个检查以确保它们被正确解除分配(它们是,并且崩溃仍然发生)来验证这一点。

Update (r2): I forgot to mention that this app is running under rather severe memory constraints (I've got a lot of images loaded at any given time and these are swapped in/out), so this may be a case of running out of memory (read on -- it's not). I'm not sure how to verify that, though, so thoughts on this would be welcome too. I did verify this by severely cutting down on the number of images being loaded and adding a check to make sure they're properly deallocated (they are, and the crash still occurs).

更新3:我以为我发现了问题。下面是我写的答案,在崩溃再次发生之前:

Update 3: I thought I found the problem. Below is the answer I wrote, before the crash happened again:

代码将(在我发布此问题后)偶尔开始退出退出代码 0 ,有时退出代码 10(SIGBUS) 0 表示没有错误,因此非常奇怪。 10 似乎意味着一切,所以这也是无益的。然而, drawInRect:调用是一个很大的暗示,当崩溃发生在那里时。

The code would (after I posted this question) occasionally start exiting with exit code 0, and sometimes with exit code 10 (SIGBUS). 0 means "no error", so that was extremely odd. 10 seems to mean a bit of everything so that was unhelpful too. The drawInRect: call was a big hint, though, when the crash happened there.

循环获取缩略图产生了大量自动释放的图像。我有一个自动释放池,但它正在包装整个for循环。我在中为循环添加了第二个自动释放池:

The looping through to get the thumbnails was generating a lot of autoreleased images. I had an autorelease pool but it was wrapping the entire for loop. I added a second autorelease pool within the for loop:

- (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。回到绘图板......

I thought the above fixed the issue, until I ran the app and it crashed on me with "exit code 0" again just earlier. Back to the drawing board...

推荐答案

事实证明,有两个答案:

It turns out, there are two answers:

必须 drawInRect:在主线程上执行单独的上下文?答案是否定的,但事实并非如此。

"Must drawInRect: for a separate context be executed on the main thread?" The answer is no, it doesn't.

然而, UIGraphicsBeginImageContext 必须。这实际上是发生崩溃的原因。在(无效)图形上下文被更改之前,崩溃没有显示出来,这就是 drawInRect:行发生崩溃的原因。

However, UIGraphicsBeginImageContext must. This in fact is the reason for the crashing that occured. The crash didn't reveal itself until the (invalid) graphics context was being altered, which is why the crash occured on the drawInRect: line.

解决方案是停止使用 UIGraphicsContext ,而是使用 CGBitmapContext 线程安全。

The solution was to stop using UIGraphicsContext and instead use CGBitmapContext, which is thread safe.

这篇关于必须drawInRect:在主线程上执行单独的上下文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆