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:
)
You should look into using NSOperation; either an NSInvocationOperation
, if you have a specific object doing the rendering, or NSBlockOperation
, 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 the drawRect:
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, call setNeedsDisplay:
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 use initByReferencingURL:
, 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 used initWithURL:
, 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 an NSImage
.
MORE:
A custom view's 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.");
}
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):
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.
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
精彩评论