将昂贵的图形卸载到后台-我可以防止drawRect清除NSView的dirtyRect吗?

时间:2018-12-01 18:21:54

标签: objective-c nsview drawrect

我有一个自定义NSView'MyView',它显示了创建成本很高的NSImage。理想情况下,此渲染应在发生背景威胁时进行,并且MyView应该在渲染完成后自行更新。

为此,我遵循了WWDC 2013, Session 215 (around 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中清除视图?

0 个答案:

没有答案