懒惰的图像绘制

时间:2011-04-26 14:19:22

标签: objective-c cocoa macos appkit

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

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

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

澄清:


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

2 个答案:

答案 0 :(得分:1)

我喜欢EGOImageView类用于这些目的。它非常容易使用并且包括一些很好的奖励,例如缓存机制。

在此处阅读有关EGOImageView的更多信息(包括Github的下载链接):

http://developers.enormego.com/view/what_if_images_on_the_iphone_were_as_easy_as_html

答案 1 :(得分:1)

你应该考虑使用NSOperation;如果您有特定对象进行渲染,则为NSInvocationOperation;如果渲染足够简单以适合单个函数,则为NSBlockOperation

如果您可以在实际访问视图drawRect:之前开始渲染,那么就这样做(也许您的应用代表会在启动时启动该过程)。否则,请检查drawRect:内容是否仍然可用;如果没有,请启动操作并继续其他绘图。当渲染对象完成其工作时,它可能会发布通知,或者,如果您向视图提供引用,请调用setNeedsDisplay:

沿着最后一句话,您还可以考虑渲染对象能够返回部分渲染的图像。我不确定渲染的性质,但有可能在某些点(每个n循环的末尾,或每n行像素)得到结果,将它们放入单独的NSImage中与最终图像大小相同(如果需要,在末尾填充),并使该部分图像可用于绘图。

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

NSImage进行子类化以实现自己的延迟加载或延迟渲染可能并不容易;它使用我认为是class cluster的一部分的辅助类,这就是为什么我建议使用一个包含并返回NSImage的“渲染器”对象。

MORE:

自定义视图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.");
}

此日志输出;注意实例化非常快,但是加载和绘图需要两分钟,在此期间什么都没画,应用程序什么都不做(旋转沙滩球):

2011-04-27 21:33:00.899 SetNeedsDisplay[80162:a0b] Entered: drawRect:
2011-04-27 21:33:00.901 SetNeedsDisplay[80162:a0b] Image instantiated.
2011-04-27 21:34:57.911 SetNeedsDisplay[80162:a0b] Image drawn.
2011-04-27 21:34:57.912 SetNeedsDisplay[80162:a0b] Bezier path drawn; exiting drawRect.