在后台线程上调用 dawRect: 会导致崩溃吗?

问题描述 投票:0回答:1

我有一些繁重的 UI 绘图操作,因此我将其传递给后台线程。我报告的崩溃大约 100% 发生在这次操作期间。当绘图在主线程上运行时,没有这样的问题,代码没有改变。

在后台绘图有风险吗?

(我正在填充 UIScrollView 内容,可能是那里的问题吗?)

iphone multithreading crash drawrect
1个回答
8
投票

首先,你不应该自己调用

drawRect:
,UIKit 会为你做这件事。你应该打电话给
setNeedsDisplay
。其次,UIKit 不是线程安全的,因此在主线程以外的任何线程上调用任何 UIKit 绘图操作都可能会使您的应用程序崩溃,正如您所经历的那样。

但是,如果您创建自己绘制的上下文,然后仅使用 CoreGraphics 调用,则 CoreGraphics 是线程安全的。因此,您可以做的是使用 CoreGraphics 在后台线程中进行耗时的绘图,在其中绘制图像上下文并将图像存储在实例变量中。然后在主线程上调用

setNeedsDisplay
并在
drawRect:
方法中简单地显示渲染图像。

所以在伪代码中(Core Graphics 版本):

- (void)redraw
{
    [self performSelectorInBackground:@selector(redrawInBackground) withObject:nil];
}

- (void)redrawInBackground
{
    CGImageRef image;
    CGContextRef context;
    
    context = CGBitmapContextCreate(..., self.bounds.size.width, self.bounds.size.height, ...);

    // Do the drawing here
    
    image = CGBitmapContextCreateImage(context);

    // This must be an atomic property.
    self.renderedImage = [UIImage imageWithCGImage:image];

    CGContextRelease(context);
    CGRelease(image);

    [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
}

- (void)drawRect:(CGRect)rect
{
    [self.renderedImage drawAtPoint:CGPointMake(0,0)];
}

UIKit 版本为:

- (void)redrawInBackground
{
    UIGraphicsBeginImageContext(self.bounds.size);

    // Do the drawing here.

    self.renderedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
}
© www.soinside.com 2019 - 2024. All rights reserved.