NSTimer scheduledTimerWithTimeInterval: repeats:NO selector method calls multiple times - iphone

I am using NSThread along with NSTimer.
My code is like this
-(void) checkForRecentAlarm
{
if ([self.alarmThread isFinished])
{
[self.alarmThread cancel];
}
self.alarmThread = [[NSThread alloc] initWithTarget:self selector:#selector(startTimerForRecentAlarm) object:nil];
[self.alarmThread start];
//[NSThread detachNewThreadSelector:#selector(startTimerForRecentAlarm) toTarget:self withObject:nil];
}
-(void)startTimerForRecentAlarm
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
self.recentAlarmTime = [NSDate date];
self.dbObject = [[RADataBaseModelManager alloc] init];
self.recentAlarmTime = [self.dbObject getMostRecentAlarmTimeFromDB];
if (self.recentAlarmTime) {
NSTimeInterval timeIntervalToAlarm = [self.recentAlarmTime timeIntervalSinceNow];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
//Fire timer every second to updated countdown and date/time
self.RATimer = [NSTimer scheduledTimerWithTimeInterval:timeIntervalToAlarm target:self selector:#selector(timerFireMethod:) userInfo:nil repeats:NO];
[runLoop run];
}
[pool release];
}
- (void)timerFireMethod:(NSTimer*)theTimer
{
[self.RATimer invalidate];
[theTimer invalidate];
self.RATimer = NULL;
theTimer = NULL;
[self playAlarm];
UIAlertView *alarmAlert = [[UIAlertView alloc] initWithTitle:#"Alarm" message:#"" delegate:self cancelButtonTitle:#"Close" otherButtonTitles:#"Snooze", nil];
[alarmAlert show];
[alarmAlert release];
alarmAlert = nil;
}
Now the problem is, my alertbox comes twice for one call in the
startTimerForRecentAlarm
method. So that the alert comes consequently twice and my view get stuck.
What will be problem here?
I am trying to implement an alarm with multiple alarm option using a single NSTimer.
Please help.
When I debug this, I can find many simultaneous threads are running on same code(UIAlertView).

I can't see any obvious reason why that would be called twice, but it does seem like an overly complex way of doing what you need to do.
Have you thought about using local notifications?
If you don't want to do that, you could refactor your code so it works like this:
1. Add a new event
2. If there's no timer or the time to the event is shorter than the time on the timer, then set the timer for this event.
3. When a timer fires, check for the next event and set a timer for that event (if there is one).

This does seem really complex. My general observation is that if you get two timer firings it's because you have two timers for some reason.
If you have multiple threads doing UIAlertView, you have another problem, because you can only (reliably) do UI from the main thread.

Related

want to loop in particular method using performselectoronmainthread

I have to loop in particluar method which do some task. I have used the method performselectoronmainthread wait until done method. Its working fine if i call it for once. But It fails when I call it in for loop. ie
this is the code:
for (int i=1;i<=3;i++) {
ip=i;
[self performSelectorOnMainThread:#selector(createThread:) withObject:ip waitUntilDone:YES];
}
-(void)createThread:(NSString*)ipIs
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"Ip address is :%#",ipIs);
[SimplePingHelper ping:ipIs target:self sel:#selector(Result:)];
[pool release];
}
- (void)Result:(NSNumber*)success {
//do some stuff
}
The problem is that this code works fine when I run this loop once and It calls Result method. But it execution path changes when I try to use loop in performSelectorOnMainThread to pass different variables into it.Then It doesnt call result method.
I am looping because I want to run these same methods on different variables but task to be performed would be same.I am also using waituntil done:YES value..but still it is not working
Any idea ?
try creating other thread
myThread = [[NSThread alloc] initWithTarget:self selector:#selector(setupTimerThread) object:nil];
[myThread start];
-(void)setupTimerThread
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
timer2 = [NSTimer timerWithTimeInterval:0.04
target:self
selector:#selector(triggerTimer:)
userInfo:nil
repeats:YES];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer2 forMode:NSDefaultRunLoopMode];
[runLoop run];
[pool release];
}
-(void)triggerTimer:
{
//this method will be called in loop set loop interval by setting the timers time duration in above method
}
EDIT :
int ip=0;
-(void)triggerTimer:
{
ip++; // till ip<=3
[self createThread:ip];
}

Problem in Background Thread in iPhone

I am using Background Thread to update one of my label
I am using the following code. But in iOS 4.0 i have learn that application saves its states and goes to background. and my application also did that work but the thread i am using stops working when i hide the application and again resumes from where i left when i reopen it. Can anybody please tell me what do I need to change in code in order to make the thread keep on running in background and change my GUI while my application is hidden. I am using this code..
-(void)startThread
{
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:#selector(setUpTimerThread) object:nil];
[thread start];
}
-(void)setUpTimerThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSTimer *timer = [NSTimer timerWithTimeInterval:3 target:self selector:#selector(triggerTimer) userInfo:nil repeats:YES];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSRunLoopCommonModes];
[runLoop run];
[pool release];
}
-(void)triggerTimer
{
NSLog(#"***Timer Called after 3 seconds*** %d",count);
self.label.text = [NSString stringWithFormat:#"count value = %d",count];
//self.titleLabel.text= [NSString stringWithFormat:#"count value = %d",count];
count = count +1;
}
Thanks
Timers won't work on relaunch of the application. What you need to do is reinitialize the timer from your appDelegate's applicationDidBecomeActive: method and make sure you shut down the timer from applicationWillEnterBackground: method

Background repeated job

I have a question about multithreading in xcode. I have searched for numerous web sites but still cannot get my app to work. I want to do a repeated job every 5sec even the Home button is pressed i.e. continue to time in background. The following is my code:
- (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:#selector(test) toTarget:self withObject:nil];
}
In test.m,
-(void)test {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(sayYeah) userInfo:nil repeats:YES];
[pool release];
}
in sayYeah.m,
-(void)sayYeah {
NSLog(#"yeah");
}
What I expect is "yeah" will continue to pop up every 5sec even the home button is pressed. But it didnt, can anyone have an idea how the multithread should be implemented? Thanks!
You can't unless your app fall is the category VOIP, audio playback or location update.
And you can't use timers.

Improper behavior of NSTimer on separate thread

I am trying to schedule NSTimer on a separate thread and this is how i am doing it.
-(void) startSpinner {
#ifdef DEBUG_MODE
NSLog(#"Starting Spinner...");
#endif
self.spinnerThread = [[[NSThread alloc] initWithTarget:self selector:#selector(scheduleSpinner) object:nil] autorelease];
[spinnerThread start];
}
-(void) scheduleSpinner {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSTimer *_spinTimer = [NSTimer scheduledTimerWithTimeInterval:SPIN_FIRE_INTERVAL target:self selector:#selector(timerFireMethod:) userInfo:nil repeats:YES];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:_spinTimer forMode:NSRunLoopCommonModes];
[runLoop addTimer:_spinTimer forMode:UITrackingRunLoopMode];
[runLoop run];
[pool release];
}
timerFireMethod spins my spinner and when a button is pressed (stop button), i invalidate the timer and exit the thread in this method. I do a polling here if spin button is pressed.
The problem is, my timerFireMethod gets called properly for the first time. Spinner spins for first time. But when i stop my spinner and start it again, spinner doesn't spins. The logs say that second time my "startSpinner" method gets called but "timerFireMethod" method is not called.
The worse is, the spinner works 5-6 times on simulator, 1 times on 2g device, 4-5 times on latest ipod. Its random.
How does this basically work? What could be the problem?
Make your NSTimer instance variable a class variable. When you invalidate it, set it to nil immediately afterwards.

Threaded NSTimer

I am aware of the many questions regarding this topic, as I myself have asked one previously however, my issue now seems to be more related to the threading part. I have the following 2 methods.
-(void) restartTimer {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.
target:self
selector:#selector(dim)
userInfo:nil
repeats:YES];
time = 31;
NSLog(#"calling restart timer");
[self performSelectorOnMainThread:#selector(timerImageUpdate) withObject:nil waitUntilDone:NO];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
[pool drain];
}
-(void) resumeTimer {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.
target:self
selector:#selector(dim)
userInfo:nil
repeats:YES];
NSLog(#"calling resume timer");
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
[pool drain];
}
The restartTimer function is called when the game begins. This works fine and the timer fires the dim selector nicely. The problem occurs when the user clicks my skip button in quick succession. [skip] updates an MKMapView and in the delegate method mapdidfinishloading the follwing is called :
[NSThread detachNewThreadSelector:#selector(restartTimer) toTarget:self withObject:nil];
When this happens it seems several timers are created and thus my dim function is called far too often giving the appearance of the single timer running really fast? What is the best way to start and restart the timer using a secondary thread? Note this problem only seems to happen if the skip button is pressed repeatedly and quickly, while it works fine if just pressed now and again?
Anyone have any ideas? Many thanks
Jules
You can use a bool to know if you have a timer running or not. When you start the timer you set it to true, when you stop the timer you set it to false. When resume timer function is called you check this variable and if it's true you do not start a new timer.
Another solution would be to limit user interaction with the button. If the button is pressed you make it inactive for a time.