懒惰的图像绘制

Eri*_*ner 5 macos cocoa objective-c appkit

我有一个需要根据需要绘制到图形上下文的对象,但是,当调用对象draw方法时,内容需要时间渲染并且可能不可用.

这通常如何实现?存储对图形上下文或视图的引用,请求绘图并在完全呈现对象内部表示时延迟绘制它?

或者是否有其他标准的可可机制来处理这个问题(例如NSImage,用a初始化时是否进行延迟绘制NSURL)?

澄清:


  • 我在MacOS上,而不是iOS
  • 使用某些NSViews -setNeedsDisplay:不是我要找的答案(NSImage不依赖-setNeedsDisplay:)

Jos*_*ell 1

您应该考虑使用NSOperation;要么是NSInvocationOperation,如果您有一个特定的对象进行渲染,或者NSBlockOperation,如果渲染足够简单以适合单个函数。

如果您可以在实际到达视图之前开始渲染drawRect:,那么就这样做(也许您的应用程序委托在启动时就开始该过程)。否则,检查drawRect:内容是否可用;如果没有,则开始操作并继续另一张图。当渲染对象完成其工作时,它可能会发布通知,或者,如果您给它返回视图的引用,则调用setNeedsDisplay:

按照最后一句的思路,您还可以考虑渲染对象能够返回部分渲染的图像。我不确定渲染的性质,但可能会在某些点(每 n 个循环的末尾,或每 n 行像素)获得结果,将其填充到NSImage与最终图像(如有必要,请在末尾进行填充),并使该部分图像可用于视图进行绘制。

更新: AnNSImage不“依赖”setNeedsDisplay:或具有视图引用,因为它不代表屏幕的一部分。它所做的只是包含图像的数据;它只能在视图绘制自己,然后“显示”——实际上绘制在屏幕上。当您使用 时initByReferencingURL:,它会存储 URL,然后当另一个对象(例如包含图像并需要显示的视图)向它询问其内容时,它会执行如果您使用 时它会执行的操作initWithURL:,该对象是打开的文件并将其内容读入内存。但它并不懒惰地绘制视图正在绘制时,它只会绘制到需要它的视图

通过子类化NSImage来实现您自己的延迟加载或延迟渲染可能并不容易;它使用我认为是类簇一部分的辅助类,这就是为什么我建议拥有一个包含并返回NSImage.

更多的:

自定义视图的drawRect

- (void)drawRect:(NSRect)dirtyRect {
    NSLog(@"Entered: %@", NSStringFromSelector(_cmd));
    // Use a nice big image of the Milky Way -- this is about 5MB
    NSImage * lazyImage = [[[NSImage alloc] initByReferencingURL:
                            [NSURL URLWithString:@"http://www.eso.org/public/archives/images/original/milkyway.jpg"]]
                           autorelease];
    NSLog(@"Image instantiated.");
    [lazyImage drawInRect:[self bounds] fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
    NSLog(@"Image drawn");  // 2 minutes later; sometimes 3 in my testing
    [[NSColor yellowColor] set];
    [[NSBezierPath bezierPathWithRect:NSInsetRect([self bounds], 4, 4)] stroke];
    NSLog(@"Bezier path drawn; exiting drawRect.");
}
Run Code Online (Sandbox Code Playgroud)

由此输出的日志;请注意,实例化非常快,但加载和绘制需要两分钟,在此期间没有绘制任何内容,应用程序也没有执行任何其他操作(旋转沙滩球):

2011-04-27 21:33:00.899 SetNeedsDisplay[80162:a0b] 输入:drawRect:
2011-04-27 21:33:00.901 SetNeedsDisplay[80162:a0b] 图像实例化。
2011-04-27 21:34:57.911 SetNeedsDisplay[80162:a0b] 绘制的图像。
2011-04-27 21:34:57.912 SetNeedsDisplay[80162:a0b] 绘制贝塞尔曲线路径;退出绘制矩形。