I have a UIView
with a UITableView
and a UIImageView
in it. The UITableView
takes up the top half of the UIView
Create a flag (BOOL) to control the updating of the image.
Clear it when you want the routine that updates the image to ignore the fact that it was called by the timer event firing. When you want the image updates to resume, just set the flag. Maybe something like this:
-(void)ImageUpdater:(NSTimer *)theTimer
{
if(image_updates_enabled)
{
// Code to update image
}
}
Since you are firing a method only every three seconds it isn't a big deal to just let the timer run.
The other thing you can to is to setup the timer so that it does not repeat. With that in place the decision to re-enable the timer could be made somewhere else in your code rather than automatically. You could even do it within the callback function and still use the "image_updates_enabled" flag if you wish.
To get access to the thread from outside the startTimerThread
method, you should add a property to your class. I would suggest property over ivar because you can have atomic accessors synthesized automatically. What you do with the timer depends on whether you want to pause or stop it.
Stopping the timer means the next time you start it, it will start with the full 3 seconds remaining. This means if the timer will fire in 1 second when you stop it, it will still take 3 seconds to fire after you start it again. However, stopping is very simple. A stopTimerThread
would be defined as follows:
- (void)stopTimerThread {
NSTimer *theTimer = self.timer;
[theTimer invalidate];
self.timer = nil;
}
Since the runloop in your other thread now has no sources, it will automatically exit and the thread will end, so you can use startTimerThread
when you want to start it again.
Pausing the timer means that, if it will fire in 1 second when you pause it, it will fire 1 second after you restart it. To do this, you will also need a property containing the time remaining before the timer fires, which will be set in stopTimerThread
and used in startTimerThread
. The implementation of stopTimerThread
is as follows:
- (void)stopTimerThread {
NSTimer *theTimer = self.timer;
NSDate *fireDate = [theTimer fireDate];
[theTimer invalidate];
self.timerTimeRemaining = - [fireDate timeIntervalSinceNow];
self.timer = nil;
}
Notice that the time remaining is set to be the negative of the time interval, since the fire date will be before now. You will also have to modify startTimerThread
to take the time remaining into account when setting up the timer.
- (void)startTimerThread {
// set up autorelease pool, get run loop
NSTimeInterval timeLeft = self.timerTimeRemaining;
if(timeLeft <= 0.0) timeLeft = 3.0;
NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:timeLeft];
NSTimer *theTimer = [[NSTimer alloc] initWithFireDate:fireDate interval:3.0 target:self selector:@selector(loadNextPhoto) userInfo:nil repeats:YES];
[runLoop addTimer:theTimer forMode:NSDefaultRunLoopMode];
self.timer = theTimer;
[theTimer release];
[runLoop run];
// clean up
}
Keep a reference to the timer you create so you can stop it when needed. The next time you need it you can just create a new timer. It sounds like the best places for you to do this are in viewDidAppear: and viewWillDisappear:. I'm not sure why you are starting the timer on a new thread. You may have a good reasons for doing so but I have never needed to do this.
//This code assumes you have created a retained property for loadNextPhotoTimer
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self startTimer];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self stopTimer];
}
- (void)startTimer {
NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:3.0] interval:3.0 target:self selector:@selector(loadNextPhoto) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
self.loadNextPhotoTimer = timer;
[timer release];
}
- (void)stopTimer {
[self.loadNextPhotoTimer invalidate];
self.loadNextPhotoTimer = nil;
}
You can use the NSTimer's invalidate
method to destroy the timer.
You'll then have to recreate it, as you did in your startTimerThread
method, when you return to the view.