Using an NSTimer to progressively draw a view

Nibbie
Posts: 3
Joined: 2009.05
Post: #1
Hi,
I'm a newbie at Objective-C and iPhone development, but I'm working my way through the books and have some simple apps working well on the simulator.

I now am working on an app where I want to draw several dots on a view, at the rate of about one dot per second. drawRect starts an NSTimer, which every second calls a function that draws the next dot. The timer quits when all dots are drawn.

The problem is that I see nothing until the timer is inactivated, when all the dots appear at the same time.

If I use [self setNeedsDisplay] after each dot is drawn, then I never see more than one dot at a time. The display, apparently, is cleared with the drawing of each new dot.

If I use [self setNeedsDisplayInRect] after each dot is drawn, using the same Rect that I used to draw the dot, it's much better, but there are still some errors, as some dots get partially cleared as the new dots are drawn.

Is there a way to just see the new dots on the screen as they are drawn?
Sorry if this is a terribly naive question!

--Steve
Quote this message in a reply
Member
Posts: 65
Joined: 2009.03
Post: #2
One way to tackle this would be to use a variable which tracks the number of milliseconds which have passed since the first dot was drawn. Once a full second has passed then the second dot is drawn and the counter is reset and so on.

At the end of the drawRect method you can store the current time in milliseconds and then deduct that value from the time at the start of the drawRect method. The result or delta can then be added to your counter variable. Once you have hit one second you can set some kind of state variable which identifies which dot should be drawn and then start the process again.

Creating an NSTimer from within the drawRect method is going to get messy, so doing the timing yourself I think is a better option.

Its normally the responsibility of the main game loop to calculate the delta and pass it to what ever needs to know the amount of time which has passed since the last update.

Hope that helps.

MikeD
Quote this message in a reply
Oldtimer
Posts: 834
Joined: 2002.09
Post: #3
What you need to do is to rethink the application a bit (not by much, bear with me). In almost all cases, it helps a lot to separate the model and the view.

Your model, in this case, is a list of all dots and whether they're visible or not. (Or just a list of dots that grow).

Your view, in this case, would be a drawRect: function that loops over the above list and draws all visible dots.

Then, outside of the drawRect:, you run a timer that messes with that list. That is, you have one function that manipulates the dot-list, and the drawRect: only draws the dots, nothing more.

It might seem wasteful to re-draw all of it every pass, but 1) it's not a problem and 2) it's the right way to do it, since you'll probably have the screen cleared every time. It will also allow you to do other stuff to the list, like move the dots or hide them again.

And, of course, this is the way to go as you get more complex. I can assure you that Doom does not run its simulation from drawRect:. Wink
Quote this message in a reply
Nibbie
Posts: 3
Joined: 2009.05
Post: #4
Wow, guys, great input. Thanks.

I guess I didn't realize in my initial reading, and it makes sense now, that a draw will show only the last CG drawing event that happened, and the view won't necessarily "remember" everything that had been drawn previously. That's why setNeedsDisplayInRect could be useful sometimes, I guess.

In case redrawing everything is not practical, say if there are a bazillion dots in locations that all had to be computed, it seems there should be a way for me to draw to a persistent but hidden image in memory, so that I can draw the next dot on the hidden image and then blit the entire hidden image to the visible view. Does that make sense? Could you direct me to a resource for reading about that?
Quote this message in a reply
Nibbie
Posts: 3
Joined: 2009.05
Post: #5
Hi,
I found the answer to my own question. CGLayer Drawing, found in the Quartz 2D Programming Guide. Set up a layer, draw to the layer, then draw from the layer to the view. Works great. Thanks again for the input.
--Steve
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  NSTimer fine, CADisplayLink having some issues monteboyd 5 9,636 Aug 31, 2010 07:05 PM
Last Post: Skorche
  Alternative to NSTimer demonpants 78 43,306 Jan 11, 2010 01:52 PM
Last Post: riruilo
  NSTimer hiccups/choppy/jerky jeonghyunhan 2 2,880 Sep 24, 2009 07:35 PM
Last Post: jeonghyunhan
  OpenGL render loop - NSTimer vs rendering thread smallstepforman 27 23,257 Feb 2, 2009 10:22 AM
Last Post: ThemsAllTook