Increased Speed while using NSTimer - iphone

I have created an animated game app, In which I am using NSTimer to move an image after a particular interval of time.
timer = [NSTimer scheduledTimerWithTImerInterval:0.2 target:self selector:#selector(MoveVirus) userinfo:nil repeats:YES];
this timer calls up the function MoveVirus, MoverVirus moves virus (an Image on screen).
It works fine in the beginning but the speed of motion automatically increases.
The increased speed of motion destroys every further logic.
I don't know what is the problem with it?
Please help to solve this problem.

NSTimer isn't necessarily meant for this sort of use...From the docs on NSTimer:
A timer is not a real-time mechanism; it fires only when one of the
run loop modes to which the timer has been added is running and able
to check if the timer’s firing time has passed. Because of the various
input sources a typical run loop manages, the effective resolution of
the time interval for a timer is limited to on the order of 50-100
milliseconds. If a timer’s firing time occurs while the run loop is in
a mode that is not monitoring the timer or during a long callout, the
timer does not fire until the next time the run loop checks the timer.
Therefore, the actual time at which the timer fires potentially can be
a significant period of time after the scheduled firing time.
A better approach, if you are moving UIImages that are contained in a UIImageView would be to use the class animation methods on UIView. You can still get the same result of moving the image after a particular time if you use the animation method that contains a delay. The method is:
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
Using this method, you can specify the time of the animation (how long it takes to animate the move of your UIImages), how long to wait before starting this animation, a set on animation options, a block of animation code, and a block that executes when the animation is complete.

Related

Running an endlessly looping animation on iOS

I have a simple UIView that draws itself using drawRect:. In order for the view to animate, the drawRect method needs to be called every say 0.05 seconds, so I use a repeating timer:
timer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self
selector:#selector(setNeedsDisplay) userInfo:nil repeats:YES];
I don't know too much about run loops, and threads, and all that system stuff, so I want to know if this is the correct way to run an animation? This timer repeats itself endlessly. Is this something I should be worried about? Will this block the main thread? What can I do to minimize overall impact on performance?
The approach is not bad, but there are other ways to do it.
The timer's target method must take the timer as an argument, so instead of setting it for setNeedsDisplay directly, you should set up a method like this:
- (void)animationTimerDidFire:(NSTimer *)timer
{
[myView setNeedsDisplay];
}
If your view will always be visible, then you can just set-and-forget the timer. On the other hand, if it may go away because you switch to a different view, you will need to invalidate and recreate the timer as needed.
The main thread of your app uses a run loop and calls out to various methods in response to events, like user taps, system notifications (e.g., memory warning), and I/O arriving. If anything the run loop calls takes a long time to return, it will hold up everything in the queue. When you set up a timer, it is added to a list and that the run loop checks it each time through; if one of the timers is ready, it calls your method.
The end result is that timers are not exact: they might not fire as often as you like, might be called late, etc. Again, if your app is pretty simple, the main run loop won't be very busy and so a timer will probably be good enough. Just make sure your animation is based on actual time elapsed between calls, rather than assuming each call happens exactly 0.05 seconds apart.
Alternatives
If your animation simply involves flipping through some static images, UIImageView has some support for this.
If creating each frame of animation takes a noticeable amount of time (and you don't want to block the main thread), you could use a background queue to draw into an image (see CGBitmapContextCreate and CGBitmapContextCreateImage), then signal the main thread when a new image is ready to display. Anything that touches a view MUST happen on the main thread, but you can do the drawing on the background.
You also might want to read up on CALayer in the QuartzCore framework. This is what the UIView objects actually manipulate to draw on the screen. You may find that, instead of drawing, you can get the effects you want by manipulating some CALayer objects and letting Core Animation do the heavy lifting (e.g., you change the color from red to blue, Core Animation takes care of fading from one to the other).
Well, if you are using an overridden or custom method, you should use recursion and a completion block for calling the animation. I find it works much better than a timer, since timers aren't always exact and can cause some animation issues if you have the animations timed for cycling.
EDIT: I don't know much about using drawRect: and calling [self setNeedsDisplay] to update it, so I can't help you in that regard. Sorry.

iPhone: NSTimer stops temporarily when a touch action is performed?

I am developing an iOS application where I trigger the NSTimer repeatedly for every 0.5 seconds and based on that timer I move a song progress bar. I handle touch events when the user touches on some images, which I keep in the same view.
However, when the user touches the images, the timer for moving the progress bar stops temporarily and continues again. Are there any problems that we should cater for when wanting to handle the timer and touch events at the same time in the same view?
Is there a reason for the temporary stoppage when touching the images?
It sounds like there is too much going on on the main thread of the app. The timer method calls are delivered on the main run loop as are the touch events. Make sure that neither your touch event handler nor your timer handlers are doing any serious computational or IO work on the main thread.
In working with the highest level audio framework in iOS (AVPlayer) it only updates the current position in the audio track once a second. So, maybe having the timer call every 0.5 seconds is overkill, maybe every 1 or 0.9 seconds would reduce the contention a bit.

UIView drawing problem

I have this big problem that i dont know how to fix. I have a UIView that i want to draw a scrolling background on. I am using NSTimer to update 30 frames per second but it seems to redraw one frame every 8 seconds. I am calling [self setNeedsDisplay] but it has no effect. I cant figure out why this is happening, does anyone have any tips?
Thanks for your time.
I have an NSTimer in my applicationDidFinishLaunching method
timer = [NSTimer scheduledTimerWithTimeInterval:0.0
target:self
selector:#selector(gameLoop:)
userInfo:nil
repeats:YES];
It's messaging this method:
-(void) gameLoop: (id) sender
{
[myView updateAll];
[myView setNeedsDisplay];
}
myView is a UIView. UpdateAll updates my code for drawing. It works fine, the problem seems to be the drawRect method is being executed so infrequently. I need to know how to make it execute 30 frames per second. I keep seeing people say that all you have to do is what i have above but setNeedsDisplay still only gets called every 8 seconds.
Thank you for your help...
Redrawing the view is an expensive operation, which will decrease performance considerably. If you can instead, just have the background as an image view move across the background using [UIView beginAnimation... or using CAAnimations.
Don't use NSTimer.
From the NS Timer reference
Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds.
I'm not an expert on the iPhone, but you probably need to look into animation on the platform to achieve the update interval you want.
It turns out that my code was just incredibly inefficient and that was causing the slow down not the timer. If you have a similar problem, make sure to test your drawRect with some simple drawing (such as drawing your Frames Per Second to the screen) before you assume it is not being executed. Thanks for viewing.

Schedule timer with NSTimer makes the task run faster than expected

I schedule a timer with NSTimer's function in viewWillAppear as follows:
minutesTimer = nil;
minutesTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:#selector(updateScrollViewItems) userInfo:NULL repeats:YES];
With this function call, I expect it to call the selector updateScrollViewItems every minute, but it does not, it update items faster than expected (around some seconds).
What is the cause of this unexpected behavior?
It might not be the direct cause of the issue you're seeing, but I can already spot one major error.
The fact that this timer is set up each time on viewWillAppear means that whenever your view appears, you're creating a new timer (and leaking the old one) which will fire 60 seconds after creation.
If your view disappears and reappears multiple times, you're going to have multiple timers all firing the same method at completely random intervals.
You need to manage the timer properly. If you want it to start when the view is first created and keep ticking/firing even when the view is not shown, then you need to create it during init, or viewDidLoad, and then be sure to stop it when you dealloc or viewDidUnload.
If you want your timer to only tick/fire when the view is the current view, then you need to ensure you're managing stopping and starting the timer appropriately on viewDidAppear and viewWillDisappear.
Also, as Williham Totland said in his answer, NSTimer shouldn't be relied upon for exact timing. This is also stated in the documentation:
A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds. If a timer’s firing time occurs while the run loop is in a mode that is not monitoring the timer or during a long callout, the timer does not fire until the next time the run loop checks the timer. Therefore, the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time.
In this case, with a time span of 60 seconds, it shouldn't be a problem that the timer is not exact, I think the issues you're seeing are because the timer isn't being managed properly.
The iPhone is a lot of things; and a neat device, however; just like any other computer, a precision timepiece it is not. However, it seems as if the method in question takes an NSTimeInterval, which is a double. You might want to change that to 60.0.
If you want your timer to only
tick/fire when the view is the current
view, then you need to ensure you're
managing stopping and starting the
timer appropriately on viewDidAppear
and viewWillDisappear.
Thanks for this info, even though I'm not the OP of this thread I was looking for an answer for a similar issue. I was scratching my head for few days, searched all over the internet but I couldn't find the answer. Finally I found this thread. This is a valuable info for me.

How to fire 10 messages per second?

Problem: I need to fire values to an object 10 times per second. I must be able to start firing and stop firing.
I've discovered that the delegate of an UIScrollView gets notified in about the same time intervals, no matter how fast the scrolling is. You can easily see that if you NSLog the deltas from the offset changes. There must be a way to start firing a message 10 times per second until something says "stop". But how?
I would look into the NSTimer class. That should allow you to set up a timer with an arbitrary time span (and stop it when desired).
I'm not much of a Cocoa developer, but I'm pretty sure you want NSTimer.
Look into [NSTimer timerWithTimeInterval:invocation:repeats:], [NSTimer invalidate], and NSRunLoop.