【问题标题】:Can invoking dawRect: on background thread cause crash?在后台线程上调用 dawRect: 会导致崩溃吗?
【发布时间】:2012-02-18 22:21:14
【问题描述】:

我有一些繁重的 UI 绘图操作,所以我将它传递给后台线程。我报告的大约 100% 的崩溃发生在此操作期间。绘图在主线程上运行时没有这样的问题,代码只是未处理。

在后台绘图有什么风险吗?

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

【问题讨论】:

    标签: iphone multithreading crash drawrect


    【解决方案1】:

    首先,你不应该自己打电话给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];
    }
    

    【讨论】:

    • What's New in iOS: iOS 4.0: UIKit Framework Enhancements: “在 UIKit 中绘制图形上下文现在是线程安全的。”
    • 跨线程传递 UIKit 提供的图形上下文仍然是不安全的。
    • 感谢您的澄清,我错过了。
    • 谢谢,我自己不是在调用 drawRect:,而是在那儿做重载。
    • 我会在主线程上做所有关于 UIKit 调用的事情,我唯一可以传递给后台(如果我理解你的话)在单独的上下文中进行自定义绘图,然后将结果 UIImage 传递给主线程(又名填充 UIKit 元素)。
    猜你喜欢
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    • 2019-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多