Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

bahlquist

macrumors member
Original poster
Oct 6, 2010
41
0
I wrote a program that used an NSTimer to send a message repeatedly to the same target. Now I want to remove the timer and just have the message sent at the start of each run loop. What is the best way to do this? If I was programming in C, I would just use a while loop.
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
I wrote a program that used an NSTimer to send a message repeatedly to the same target. Now I want to remove the timer and just have the message sent at the start of each run loop. What is the best way to do this? If I was programming in C, I would just use a while loop.

This doesn't make sense. The run loop is executed exactly as often as it needs to, no more, and no less. There would be no guarantee how often your code would get executed. So the best way to do this is - don't. But why don't you tell us what you actually want to achieve?
 

GorillaPaws

macrumors 6502a
Oct 26, 2003
932
8
Richmond, VA
I suspect you might want to create some form of delegation or notification so your method is called when a certain periodic action occurs. As gnasher729 has said, let us know what you're trying to accomplish.
 

bahlquist

macrumors member
Original poster
Oct 6, 2010
41
0
I just want the same method called repeatedly. In C:

Code:
while(1){myFunction();}
 

chown33

Moderator
Staff member
Aug 9, 2009
10,747
8,421
A sea of green
I just want the same method called repeatedly. In C:

Code:
while(1){myFunction();}

That's how you do it in Objective-C, too.

If you're asking how to call your function every time through a run-loop, or as fast as possible with a run-loop, then you'll have to clarify by explaining which of those you want.

Either way, it will not be identical to the while(1) loop. The reason it won't be identical is that a while(1) never pauses or breaks or does anything else. A run-loop may. If that doesn't make sense, then you should first study run-loops more. Then come up with a more precise and more detailed explanation of exactly what should happen, in what order, and at what rate. As given, your description is too vague to determine exactly what you want to happen. In particular, "at the start of each run loop" is unclear.

In studying run-loops, you should also read about CFRunLoop, not just NSRunLoop. You may also find CFRunLoopObserver to be useful.
http://developer.apple.com/library/....html#//apple_ref/doc/uid/10000057i-CH16-SW22
http://developer.apple.com/library/...e/reference.html#//apple_ref/doc/uid/20001442
 
Last edited:

bahlquist

macrumors member
Original poster
Oct 6, 2010
41
0
I am animating, in an OpenGL context, objects that bounce off each other. The method that I want called repeatedly is the method that updates the location of each object. At the end of the update method is
Code:
[self setNeedsDisplay:YES];
. I want the update method called once every time through the run loop. Now, according to my understanding of run loops, if I stick the code
Code:
while(1){update();}
inside a method that will be called, like, say, "awakeFromNib", then the run loop will not complete because of the infinite loop. I do not want this to happen because I want "drawRect" to be called. In any case, it seems that I should work within the structure run loop.

These are the details. In short: I want a method called once each time through the run loop. If this request doesn't make sense (and I really think it does), please tell me explicitly what my error is.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,747
8,421
A sea of green
You're animating. The periodic timer was already correct. Go back to it.

I don't see what you were hoping to gain by eliminating a timer. It's animation; it's supposed to be periodic.


EDITED TO ADD:
In short: I want a method called once each time through the run loop. If this request doesn't make sense (and I really think it does), please tell me explicitly what my error is.
The error is in specifying "once each time through the run loop".

Go read "The Run Loop Sequence of Events":
http://developer.apple.com/library/....html#//apple_ref/doc/uid/10000057i-CH16-SW22

Note Step 7 is "Put the thread to sleep until...". Without a periodic timer, how would your animation be regular? Yet if you have a periodic timer, why do you need anything else other than that?

Also note that the loop may repeat several times very rapidly, if there are multiple pending tasks after a wakeup and expiration isn't reached (Step 9). If your update function is really being called once each time through the run loop, it will be called several times in rapid succession. This will occur at an irregular (untimed) rate. What will that do to the animation?
 
Last edited:

HiRez

macrumors 603
Jan 6, 2004
6,250
2,576
Western US
Also, you should probably be using CADisplayLink instead of NSTimer to trigger your animation updates as it is more accurate and synchronized to the display's refresh interval.
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
Also, you should probably be using CADisplayLink instead of NSTimer to trigger your animation updates as it is more accurate and synchronized to the display's refresh interval.

but then you introduce thread safety issues, which may be a bit much at this point :)

EDIT: oops, I'm thinking CGDisplayLink.
 
Last edited:

bahlquist

macrumors member
Original poster
Oct 6, 2010
41
0
chown33, I would appreciate it if you refrained from responding to my posts (seriously). Although you have helped me out at least once, on average you cause the discussion in my posts to degenerate. In particular, I don't want to have to explain why I don't want to use a timer and then argue about it.

Please, no one has addressed my original question yet.
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
chown33, I would appreciate it if you refrained from responding to my posts (seriously). Although you have helped me out at least once, on average you cause the discussion in my posts to degenerate. In particular, I don't want to have to explain why I don't want to use a timer and then argue about it.

Please, no one has addressed my original question yet.

It's not a problem to know nothing, but it is a problem to refuse to learn. You were given the best possible advice, and you ask the person giving it not to respond to your posts?
 

Catfish_Man

macrumors 68030
Sep 13, 2001
2,579
2
Portland, OR
chown33, I would appreciate it if you refrained from responding to my posts (seriously). Although you have helped me out at least once, on average you cause the discussion in my posts to degenerate. In particular, I don't want to have to explain why I don't want to use a timer and then argue about it.

Please, no one has addressed my original question yet.

Actually they have, you just don't understand the answer.

To answer the question very directly: use a runloop source. An example of a runloop source is a timer. You could also write your own custom CFRunLoopSource that signaled readiness as soon as it fired. That would probably screw up your animation though.

Probably the simplest way to do this is to use the -performSelector:afterDelay: method and pass 0 for the delay.

However, that will use a timer internally, which is apparently bad?
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
chown33, I would appreciate it if you refrained from responding to my posts (seriously). Although you have helped me out at least once, on average you cause the discussion in my posts to degenerate. In particular, I don't want to have to explain why I don't want to use a timer and then argue about it.

Please, no one has addressed my original question yet.

It makes me sad to reply to someone who is so willing to reject help. chown33 linked to a document that explains very specifically how one would get something to occur at various points in the run loop. Specifically, you could add a run loop observer to the entrance to the run loop (for example). The document chown33 linked to provides a link to:
http://developer.apple.com/library/...e/reference.html#//apple_ref/doc/uid/20001442

This is the reference for setting up a run loop observer that will fire when you have requested. Of course, as others have explained, even if you read that and set it up you are not going to get the desired behavior because of the nature of the run loop. It's not doing what you're expecting. People are trying to warn you that the timer is a valid approach and there's no reason to abandon it and you are expressing that you do not want good advice, you want to know how to do the wrong thing. Those documents will tell you, but when you discover that tying into the run loop is not what you want in this case and come back looking for more help, you're going to have a harder time getting any when you are actively discouraging it.

In any case, good luck with this project and in getting assistance in the future.

-Lee
 

vocaro

macrumors regular
Mar 5, 2004
120
0
chown33, I would appreciate it if you refrained from responding to my posts (seriously). Although you have helped me out at least once, on average you cause the discussion in my posts to degenerate.

What you perceive as degeneration is simply mass confusion caused by your own posts. You seem unable to fully explain your situation and are too quick to reject the sound advice offered to you.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,747
8,421
A sea of green
chown33, I would appreciate it if you refrained from responding to my posts (seriously). Although you have helped me out at least once, on average you cause the discussion in my posts to degenerate. In particular, I don't want to have to explain why I don't want to use a timer and then argue about it.

You asked for an explanation of what your error was in this:
If this request doesn't make sense (and I really think it does), please tell me explicitly what my error is.
I gave an explanation of the error. If you wish to challenge my explanation, or refute it by pointing out errors in my explanation, then please do so. I did double-check the reference docs before writing the explanation, but I could have made a mistake. Otherwise all I can do is refer you to Apple's documentation, and note that the questions I asked are not merely rhetorical devices. They are simple logical questions that arise directly from how a run-loop works. Without a timer of some kind, how do you propose to have regular periodic animated frames? That seems like a fundamental question to me.

Perhaps you should explain why you don't want to use a timer, given the context of your error. If a run-loop cannot be made to do what you want without using a timer of some kind, then it seems logical to me that the reasons for not using a timer be explained.
 

BadWolf13

macrumors 6502
Dec 17, 2009
271
0
While I know nothing about animation in Obj-C or Cocoa, I have used a do...while loop in my Obj-C programs, the same way I used them in C++. They work just fine, and the context is exactly the same.
 

GorillaPaws

macrumors 6502a
Oct 26, 2003
932
8
Richmond, VA
chown33, I would appreciate it if you refrained from responding to my posts (seriously). Although you have helped me out at least once, on average you cause the discussion in my posts to degenerate. In particular, I don't want to have to explain why I don't want to use a timer and then argue about it.

Please, no one has addressed my original question yet.

The arrogance of that response is appaling. Read this article--at least twice.
 

bahlquist

macrumors member
Original poster
Oct 6, 2010
41
0
Animating something by updating across irregular time intervals is not a problem: just calculate how much time has elapsed since the last update, and update using that time factor. If I am animating objects that interact with each other by colliding (in a physically realistic way), I may run into trouble if too many interactions occur in a short period of time, for the time needed to calculate the collisions may be longer than the ideal update interval length. In this case I want to compute the time of the collisions and update the locations over the whole sequence of collisions - but draw nothing until everything in the model is current. I will know when everything is current when I check for the next collision and find that it occurs in the (relatively) distant future. It is then that I will do the drawing (after one final update that coordinates the model with system time). I wouldn't want to wait to draw as I may have already waited to draw while sorting out the collisions.

It seems my answer does lie with CFRunLoopObserver, which is described in a link that was posted earlier:

http://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFRunLoopObserverRef/Reference/reference.html%23//apple_ref/doc/uid/20001442

In particular, the "The Run Loop Sequence of Events" is helpful (I tried to look for this earlier, but didn't know what to search for):

1. Notify observers that the run loop has been entered.
2. Notify observers that any ready timers are about to fire.
3. Notify observers that any input sources that are not port based are about to fire.
4. Fire any non-port-based input sources that are ready to fire.
5. If a port-based input source is ready and waiting to fire, process the event immediately. Go to step 9.
6. Notify observers that the thread is about to sleep.
7. Put the thread to sleep until one of the following events occurs:
* An event arrives for a port-based input source.
* A timer fires.
* The timeout value set for the run loop expires.
* The run loop is explicitly woken up.
8. Notify observers that the thread just woke up.
9. Process the pending event.
* If a user-defined timer fired, process the timer event and restart the loop. Go to step 2.
* If an input source fired, deliver the event.
* If the run loop was explicitly woken up but has not yet timed out, restart the loop. Go to step 2.
10. Notify observers that the run loop has exited.
 

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
Animating something by updating across irregular time intervals is not a problem: just calculate how much time has elapsed since the last update, and update using that time factor. If I am animating objects that interact with each other by colliding (in a physically realistic way), I may run into trouble if too many interactions occur in a short period of time, for the time needed to calculate the collisions may be longer than the ideal update interval length. In this case I want to compute the time of the collisions and update the locations over the whole sequence of collisions - but draw nothing until everything in the model is current. I will know when everything is current when I check for the next collision and find that it occurs in the (relatively) distant future. It is then that I will do the drawing (after one final update that coordinates the model with system time). I wouldn't want to wait to draw as I may have already waited to draw while sorting out the collisions.

Do you think this is the first time someone has ever tried to animate and calculate collisions? Technologies like CADisplayLink were created for just this kind of situation. Everything I've ever read about OpenGL uses a "time since last frame" approach to animation, often breaking up the modeling function from the displaying function so you can iterate over the model multiple times if too much time has passed since the last display.

Seems like maybe a book is more called for than a forum post right now.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,747
8,421
A sea of green
Animating something by updating across irregular time intervals is not a problem: just calculate how much time has elapsed since the last update, and update using that time factor. If I am animating objects that interact with each other by colliding (in a physically realistic way), I may run into trouble if too many interactions occur in a short period of time, for the time needed to calculate the collisions may be longer than the ideal update interval length. In this case I want to compute the time of the collisions and update the locations over the whole sequence of collisions - but draw nothing until everything in the model is current. I will know when everything is current when I check for the next collision and find that it occurs in the (relatively) distant future. It is then that I will do the drawing (after one final update that coordinates the model with system time). I wouldn't want to wait to draw as I may have already waited to draw while sorting out the collisions.
If you had posted that explanation to begin with, we all would have known why you removed the timer. Then I wouldn't have told you to go back to it. And I still would have pointed you to the CFRunLoop and CFRunLoopObserver reference docs.

It seems my answer does lie with CFRunLoopObserver, which is described in a link that was posted earlier:

http://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFRunLoopObserverRef/Reference/reference.html%23//apple_ref/doc/uid/20001442

In particular, the "The Run Loop Sequence of Events" is helpful (I tried to look for this earlier, but didn't know what to search for):
You're welcome.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.