2012-02-18 63 views
0

我有一些沉重的UI繪圖操作,所以我把它傳遞給後臺線程。在這次行動中,大約有100%的事故報告發生。當繪圖在主線程上運行時,沒有出現這樣的問題,代碼只是解開了。可以調用dawRect:在後臺線程導致崩潰?

在後臺繪製任何風險?

(我填充UIScrollView的內容,可能是問題嗎?)

回答

7

首先,你不應該叫drawRect:自己,UIKit的會替你。你應該打電話給setNeedsDisplay。其次,UIKit不是線程安全的,因此在主線程以外的任何線程上調用任何UIKit繪圖操作都會導致應用程序崩潰,就像您遇到過的那樣。

但是,如果您創建上下文以自己繪製並僅使用CoreGraphics調用,則CoreGraphics是線程安全的。所以你可以做的是在CoreGraphics的後臺線程中繪製圖像,並將圖像存儲在實例變量中。然後在主線程上調用setNeedsDisplay,並簡單地在您的drawRect:方法中顯示渲染圖像。

因此,在僞代碼(核芯顯卡版):

- (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]; 
} 
+0

[什麼在iOS的新功能:iOS的4.0:UIKit框架的改進(HTTPS: //developer.apple.com/library/ios/releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html#//apple_ref/doc/uid/TP40009559-SW29):「在UIKit中繪製圖形上下文現在是線程安全的。「 – 2012-02-18 22:34:31

+1

雖然跨線程傳遞UIKit提供的圖形上下文仍然不安全。 – 2012-02-18 22:35:40

+0

感謝您的澄清,我錯過了。 – DarkDust 2012-02-18 22:47:01