NSTimer Issue : NStimer being called continuously after 2 seconds --- - iphone

I am using simple code to start a repetitive timer which calls a method after every 30 seconds.
[NSTimer scheduledTimerWithTimeInterval:30 target:self selector:#selector(refresh) userInfo:nil repeats:YES];
It starts properly but after some time it calls the 'refresh' method after every 2 or 3 seconds randomly. I am not modifying the timer or anything anywhere else in the code . Any guess what could be possibly going wrong .....
Thank You!!

Is it possible that this code is being run more than once, thus setting up multiple instance of a timer with a 30 second timeout, all firing at different times?
If that isn't the case, is it possible that some of the processing you're doing is perhaps blocking the run loop and causing the timer events to queue up?
I would suggest checking those possibilities.

Related

Stop NSTimer Keeps Increasing Intervals

I have a strange issue with my countDown timer. This timer is counts down from a set time (i.e. 60 seconds). This bit of code is placed in myViewDidLoad method. Everything works unless I go back and load the view again. Every time the view loads, there is an increment of 1 second in the countdown.
For example:
First Load: 60, 59, 58...
Second Load: 60, 58, 56...
Third Load: 60, 57, 54...
My code is below. Does anyone know why this is happening? Do I need to release something somewhere? Thank you!
countDown=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:#selector(TimeOver) userInfo:nil repeats:YES];
Each time your view loads, you create a new timer, but the old ones still exist. In your timer's action method, TimeOver, you are decrementing an index variable that keeps track of the seconds, and each timer runs that method every time it fires. So, if you have three timers, the index will decrease by three each time.
You need to either not create new a new timer whenever your view loads or, better, destroy the timer when your view disappears:
[countDown invalidate];
countdown = nil;
and recreate it when it reappears.
Also, be aware that your timer's action method has an incorrect signature. It should be a method which returns nothing and takes one argument, which is the timer itself, like so:
- (void)timeOver: (NSTimer *)tim;
Also, Cocoa methods should not start with capital letters.

NSTimer Reliable Alternatives

I have an application that is supposed to log certain things every 1 second and I'm currently using NSTimer, but if my application transitions screens (or almost anything else, really) it slows down the timer a little bit making for inaccurate readings.
What is a reliable alternative to use? My current code is as follows:
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(update) userInfo:nil repeats:YES];
NSTimer is not guaranteed to fire exactly on time, ever. But you can use an NSTimer in a much more reliable way than you are now. When you use scheduledTimerWithTimeInterval you create an NSTimer which is scheduled in the run loop for NSDefaultRunLoopMode. This mode is paused when the UI is being used, so your timers won't fire when there is user interaction. To avoid this pause use the mode NSRunLoopCommonModes. To do this you will have to schedule the timer yourself like so:
timer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(update) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
You could:
Put the NSTimer in a different thread (it may not be affected by the UI that way)
Decrease the interval (say 0.1 second) and, in your logging function, check if it is the "right" time to log what you want.

How to work with NSTimer

Im using alot of timers in my application. For recording time, moving object, fading etc. I use the same timer for several puposes in the same view at different times. How should I declare and invalidate or release my timers properly?
Atm Im declaring the timers like this:
fadeTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(bortInfo) userInfo:nil repeats:YES];
and as soon as im not using it im doing this:
[fadeTimer invalidate];
fadeTimer = nil;
The retain count when im leaving the view is 0 on every timer. Should i release the timer in the dealloc aswell? My app runs quite good, but from time to time it crashes.
The clockTimer that i use for updating a label with the time uses
[[NSRunLoop mainRunLoop] addTimer:clockTimer forMode:NSRunLoopCommonModes];
Do i need to do anything with this mainLoop once i invalidate the clockTimer?
All in all please support me with some info about working with timers.
Thank you very much!
Joakim
You're not retaining your timers properly - if you want to refer to them again you should retain them. I'd do this with a property i.e. in your header file
#property (nonatomic, retain) NSTimer *fadeTimer;
and change your code to say
self.fadeTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(bortInfo) userInfo:nil repeats:YES];
// Put this whenever you want to remove your timer and in your dealloc method.
[fadeTimer invalidate];
self.fadeTimer = nil;
This will make sure that your timer is retained by your object. Otherwise you just have to hope that the timer stays around and doesn't get autoreleased by the iPhone. And as you say it's crashing occasionally, this might be the reason ;)
I'm afraid I don't know much about run loop but am confused why your don't just use a normal NSTimer to schedule things - why bother interacting with the run loop at all?
Scheduled timers are retained by the run loop, and retain their target. If you want to retain the timer, you have to jump through a few hoops to prevent a retain cycle (I wrote a non-retaining proxy class, which is a bit messy but it works).
Don't manipulate the run loop unless you know what you're doing (I don't). A "scheduled" timer is already added to the main run loop. If you're generating clockTimer like fadeTimer, then it's being added to the run loop twice.
"from time to time it crashes" doesn't help anyone. Run it in the debugger and see where it crashes. It might even print some messages to the console if you're lucky.
*also you can use and this is a better and optimize way to write this line
if (theTimer != nil) {
if([theTimer isValid]){
[theTimer invalidate];
}
theTimer = nil;
}*

NSTimer selector calling

Can someone explain to me how exactly the NSTimer behavior is?
Basically I want to know if there is a way to always have the NSTimer event happen. Event if there is currently something executing.
For example, in:
NSTimer* testTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(testMethod) userInfo:nil repeats: NO];
for (int i=0; i<9999; i++) {
NSLog(#"%i", i);
}
testMethod will never be executed since the for loop is being executed when the event fires.
When the timer fires, it's selector is added to the run loop to be executed as soon as possible.
However, you're creating a loop so the run loop never gets a change to do the timer's selector resulting in what you're seeing - the app waits for the loop to finish before running your timer's selector.
If you have a long running task, it's best to put it into a new thread - try looking at performSelectorInBackground and reading up on threading in objective-c.

iPhone Syncing a time sequence with music

I'm using AVAudioPlayer to play music in my iPhone app.
In a class that I wrote I have an array that contains random ascending integers. (2, 4, 9, 17, 18, 20,...)
These integers represent times in the song at which a certain event should occur. So if you take the above array, after 2 seconds of the song playing, some method should be called. After 4 seconds, another method should be called. And so on.
I have tried using a repeating NSTimer:
NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerTick) userInfo:nil repeats:YES];
Everytime it fires, it checks whether the value of the Audioplayer and of the current arrayindex are the same:
- (void) timerTick {
if([[myArray objectAtIndex:currentIndex] intValue] == (int)(player.currentTime)) {
//here the event-method is called
currentIndex++;
}
}
This code actually works, but only for some time. After some time however, myTimer and the timer that controls the musicplayer are out of sync. So it misses an element of myArray and an infinite loop starts. I don't know exactly why they get out of sync, but I think it could be because the timer and the player aren't being started at exactly the same time or maybe because of short performance lags.
I think I have to approach this in a totally different way. Is key-value observing a way to do this? I could add my class as an observer to the player object, so that it gets notified when the player.currentTime value changes. But that would cause a LOT of notifications to be send and I think it would be really bad for performance.
Any help much appreciated!
Ok here is my solution: I found an open source app that does almost the same thing my app should do, which helped me a lot.
I'm going to stick with the code I already have, with a little modification it should be precise enough for my purposes. Here it is:
currentIndex = 0;
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(timerTick) userInfo:nil repeats:YES];
- (void) timerTick {
if(timerRunning){
if([[myArray objectAtIndex:currentIndex] intValue] <= (int)(player.currentTime*100)) {
//some event code
currentIndex++;
}
}
}
The important change is from == to <= in the if-condition. When it gets asynchronous and misses an element of myArray, the error is corrected the next hundredth of a second. That's good enough.
Thanks for your help!
It could be that the timers are reasonably in sync, but your code just takes to long to execute (i.e: longer then 1 second).
Couldn't you just use the timer of the musicplayer, and spawn a thread each time an event should occur? This way the timer stays uninterrupted, and your thread will do what it needs to do (lets say the heavy stuff).
If you reall y need two timers, I guess you could create a background threads that keeps those two timers in sync, but I think you're asking for trouble there..
Real world synchronization with music is very hard because users can notice mis-syncs of just a tenth of a second or less. You might find that AVAudioPlayer is to simple for what you need. You might have to control the rate the music plays using AudioQueueServices so that you can sync the music to the code instead of the other way around. You could see time to fire your code coming up and then start the methods before the music actually plays. Done skillfully this would sync the music most of the time.