懒惰的图像绘制
我有一个需要按需绘制到图形上下文中的对象,但是,内容需要时间来渲染,并且在调用对象绘制方法时可能不可用。
这一般是如何实现的?存储对请求绘制的图形上下文或视图的引用,并在对象内部表示完全渲染时延迟将其绘制到那里?
或者是否有其他标准的可可机制来处理这个问题(例如 NSImage
在使用 NSURL
初始化时执行延迟绘制)?
澄清:
- 我在 MacOS 上,而不是 iOS
- 使用一些
NSView
s-setNeedsDisplay:
不是我正在寻找的答案(NSImage
不依赖-setNeedsDisplay:
)
I have an object that needs to draw into a graphic context on demand, however, the content needs time to render and might not be available when the objects draw method is invoked.
How is this generally accomplished? Store a reference to the graphics context or view that requested drawing and draw it there delayed when the objects internal representation is completely rendered?
Or are there other standard cocoa mechanisms to handle this (for instance NSImage
does lazy drawing when initialized with a NSURL
)?
Clarifications:
- I am on MacOS, not iOS
- Using some
NSView
s-setNeedsDisplay:
is not the answer I am looking for (NSImage
doesn't rely on-setNeedsDisplay:
)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您应该考虑使用 NSOperation;如果您有一个特定的对象进行渲染,则可以是 NSInvocableOperation;如果渲染足够简单,可以放入单个函数中,则可以是
NSBlockOperation
。如果您可以在实际到达视图的
drawRect:
之前开始渲染,那么就这样做(也许您的应用程序委托在启动时就开始该过程)。否则,检查drawRect:
中内容是否可用;如果没有,则开始操作并继续另一张图。当渲染对象完成其工作时,它可能会发布通知,或者,如果您给它一个返回视图的引用,请调用setNeedsDisplay:
按照最后一句的思路,您还可以考虑您的渲染对象能够返回部分渲染的图像。我不确定渲染的性质,但可能会在某些点(每 n 个循环的末尾,或每 n 行像素)获得结果,将其填充到单独的
NSImage< /code> 与最终图像的大小相同(如有必要,请在末尾进行填充),并使该部分图像可用于视图进行绘制。
更新:
NSImage
不“依赖”setNeedsDisplay:
或具有视图引用,因为它不代表屏幕的一部分。它所做的只是包含图像的数据;它只能在视图内绘制自己,然后“显示”——实际上绘制在屏幕上。当您使用initByReferencingURL:
时,它会存储 URL,然后当另一个对象(例如包含图像并需要显示的视图)向它请求其内容时,它会执行其本来应该执行的操作如果您使用了initWithURL:
,即打开文件并将其内容读入内存,则完成。但它并不懒惰地绘制;它仅在视图正在绘制时绘制到需要它的视图中。子类化
NSImage
来实现您自己的延迟加载或延迟渲染可能并不容易;它使用我认为是 类簇,这就是为什么我建议使用一个包含并返回 NSImage 的“渲染器”对象。更多:
自定义视图的
drawRect
:由此输出的日志;请注意,实例化非常快,但加载和绘制需要两分钟,在此期间没有绘制任何内容,应用程序也没有执行任何其他操作(旋转沙滩球):
You should look into using NSOperation; either an
NSInvocationOperation
, if you have a specific object doing the rendering, orNSBlockOperation
, if the rendering is simple enough to fit into a single function.If you can start rendering before you actually get to your view's
drawRect:
, then do that (maybe your app delegate starts the process right at launch). Otherwise, check in thedrawRect:
whether the content is available yet; if not, start the operation and continue with the other drawing. When the rendering object finishes its work, it will probably either post a notification or, if you give it a reference back to the view, callsetNeedsDisplay:
Along the lines of your last sentence, you could also consider your rendering object being able to return a partially-rendered image. I'm not certain of the nature of your rendering, but it may be possible to get the results at certain points (the end of every n loops, or every n lines of pixels), stuff that into a separate
NSImage
of the same size as the final image (padding at the end if necessary), and make this partial image available to the view for drawing.UPDATE: An
NSImage
doesn't "rely on"setNeedsDisplay:
or having a view reference because it doesn't represent a piece of the screen. All it does is contain the data for an image; it can only draw itself inside a view, which is then "displayed" -- actually painted on the screen. When you useinitByReferencingURL:
, it stores the URL, and then when another object (like a view that contains the image and needs to be displayed) asks it for its contents, it does what it would've done if you had usedinitWithURL:
, which is open the file and read its contents into memory. It doesn't draw lazily, though; it only draws into the view that wants it, when that view is drawing.Subclassing
NSImage
to implement your own lazy loading or lazy rendering may not be easy; it uses helper classes that I believe are part of a class cluster, which is why I suggest having a "renderer" object which contains and returns anNSImage
.MORE:
A custom view's
drawRect
:The log output from this; notice that the instantiation is very quick, but the loading and drawing takes two minutes, during which nothing is drawn and the app does nothing else (spinning beach ball):
我喜欢用于这些目的的 EGOImageView 类。它确实很容易使用,并且包含一些不错的好处,例如缓存机制。
在此处阅读有关 EGOImageView 的更多信息(包括来自 Github 的下载链接):
http://developers.enormego.com/view /what_if_images_on_the_iphone_were_as_easy_as_html
I'm fond of the EGOImageView class for these purposes. It's really easy to use and includes some nice bonuses as will, e.g. a caching mechanism.
Read more about EGOImageView here (includes a download link from Github):
http://developers.enormego.com/view/what_if_images_on_the_iphone_were_as_easy_as_html