У меня есть пользовательский 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?