I am customizing my drawRect: method, which serves to draw a NSImage if it has been “loaded” (loading taking a few seconds worth of time because I’m grabbing it from a WebView), and putting off drawing the image till later if the image has not yet been loaded.
- (void)drawRect:(NSRect)dirtyRect
{
NSImage *imageToDraw = [self cachedImage];
if (imageToDraw != nil) {
[imageToDraw drawInRect:dirtyRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil];
} else {
//I need help here
[self setNeedsDisplay:YES];
}
}
My question is how to do the latter. [self cachedImage] returns nil if the image is unavailable, but anytime within the next few seconds it may become available and at that time I want to draw it because the custom view is already on screen.
My initial instinct was to try calling [self setNeedsDisplay:YES]; if the image wasn’t available, in hopes that it would tell Cocoa to call drawRect again the next time around (and again and again and again until the image is drawn), but that doesn’t work.
Any pointers as to where I can go from here?
EDIT:
I am very much aware of the delegate methods for WebView that fire when the loadRequest has been completely processed. Using these, however, will be very difficult due to the structure of the rest of the application, but I think I will try to somehow use them now given the current answers. (also note that my drawRect: method is relatively light weight, there being nothing except the code I already have above.)
I currently have about 10+ custom views each with custom data asking the same WebView to generate images for each of them. At the same time, I am grabbing the image from an NSCache (using an identifier corresponding to each custom view) and creating it if it doesn’t exist or needs to be updated, and returning nil if it is not yet available. Hence, it’s not as easy as calling [view setNeedsDisplay:YES] from - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame or another method.
This would be incredibly inefficient, even if it worked.
So, when that happens, call
[view setNeedsDisplay:YES].If you have no means of directly determining when the image becomes available, you’ll have to poll. Set up a repeating
NSTimerwith an interval of something reasonable — say 0.25 second or so. (This is also pretty inefficient, but at least it’s running only 4 times per second instead of 60 or worse. It’s a tradeoff between two factors: how much CPU and battery power you want to use, and how long the delay is between the time the image becomes available and the time you show it.)Even if you do nothing at all in
-drawRect:, Cocoa still needs to do a lot of work behind the scenes — it needs to manage dirty rects, clear the appropriate area of the window’s backing store, flush it to the screen, etc. None of that is free.