Может ли вызов dawRect: в фоновом потоке вызвать сбой? - PullRequest
0 голосов
/ 19 февраля 2012

У меня есть тяжелые операции рисования пользовательского интерфейса, поэтому я передал его фоновому потоку.Около 100% моих зарегистрированных аварий произошли во время этой операции.Не было таких проблем, когда рисование выполнялось в основном потоке, код просто не изменялся.

Есть ли риск рисования в фоновом режиме?

(я заполняю содержимое UIScrollView, можетпроблема есть?)

1 Ответ

7 голосов
/ 19 февраля 2012

Прежде всего, вы не должны звонить 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];
}
...