Разгрузка дорогостоящего чертежа в фоновом режиме - могу ли я помешать drawRect очистить NSView dirtyRect? - PullRequest
0 голосов
/ 01 декабря 2018

У меня есть пользовательский NSView «MyView», который отображает NSImage, который стоит создать дорого.В идеале этот рендеринг должен происходить на фоне угрозы, а MyView должен обновляться сам, когда рендеринг завершен.

Чтобы достичь этого, я последовал предложению в WWDC 2013, Сессия 215 (около 4:00) .

Это работает так: Когда вызывается drawRect иизображение еще не создано, рендеринг запускается в фоновой очереди.Там изображение создается, сохраняется в переменной экземпляра и снова вызывается setNeedsDisplay (в главном потоке), чтобы пометить представление как грязное.Это вызовет drawRect во второй раз, когда изображение теперь присутствует и может быть нарисовано:

- (void)drawRect:(NSRect)dirtyRect
{
    // Do we have an image?
    if( self.image )
    {
        // Yes, we can draw the image (and invalidate it right away for demo purposes)
        [self.image drawInRect:self.bounds];
        self.image = nil;
    }
    else
    {
        // No, we have to async render the image first and mark the view as dirty afterwards
        CGSize imageSize = self.bounds.size;
        dispatch_async( dispatch_get_global_queue( QOS_CLASS_USER_INTERACTIVE, 0 ), ^
                       {
                           self.image = [self _renderImageWithSize:imageSize];

                           dispatch_async( dispatch_get_main_queue(), ^
                                          {
                                              [self setNeedsDisplayInRect:dirtyRect];
                                          });
                       });
    }
}


- (NSImage *)_renderImageWithSize:(NSSize)size
{
    // Simulate expensive image rendering (just for demo purposes)
    NSBitmapImageRep * bitmapRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil pixelsWide:size.width pixelsHigh:size.height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:0 bitsPerPixel:32];

    NSGraphicsContext * context = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmapRep];
    [NSGraphicsContext saveGraphicsState];
    [NSGraphicsContext setCurrentContext:context];

    // Draw oval with random hue.
    float hue = ( (float)( labs( random() % 100 )) / 100.0 );
    [[NSColor colorWithHue:hue saturation:0.5 brightness:1.0 alpha:1.0] setFill];
    [[NSBezierPath bezierPathWithOvalInRect:NSMakeRect( 0.0, 0.0, size.width, size.height )] fill];

    [NSGraphicsContext restoreGraphicsState];

    NSImage * image = [[NSImage alloc] init];
    [image addRepresentation:bitmapRep];

    // Simulate super-expensive rendering
    sleep( 1 );

    return image;
}

Этот код работает нормально, но создает раздражающее мерцание.Кажется, что вид очищается при первом вызове drawRect.Он остается очищенным до тех пор, пока второй drawRect фактически не отрисовывает визуализированное изображение.

Конечно, я мог бы просто нарисовать старое изображение, но я бы предпочел не рисовать устаревшие данные без необходимости.

Есть лиспособ предотвратить очистку вида в drawRect?

...