Countdown timer using NSTimer in "0:00" format
I have been researching for days on how to do this and nobody has an answer.
I am creating an app with 5 timers on the same view. I need to create a timer that counts down from "15:00" (minutes and seconds), and, another that counts down from "2:58" (minutes and seconds). The 15 minute timer should not repeat, but it should stop all other timers when it reaches "00:00." The "2:58" timer should repeat until the "15:00" or "Game Clock" reaches 0. Right now, I have scrapped almost all of my code and I'm working on the "2:58" repeating timer, or "rocketTimer."
Does anyone know how to do this?
EDIT 2: My simulator will not even run the app so I currently have no idea if the timer is actually working or not, but from my previous attempts, it has not worked. It doesn't show up in the format that I want and it counts down by 2's (from the last time it actually worked). The problem is, also, that I'm not fluent in objective-C. I can write pseudocode all day, just like everyone else, but I cannot put what I want into code because I do not fully understand the NSTimer.
EDIT:
In my output, I get this error "terminate called after throwing an instance of 'NSException'"
and this error?
Here is my code:
#import <UIKit/UIKit.h>
@interface FirstViewController : UIViewController {
//Rocket Timer
int totalSeconds;
bool timerActive;
NSTimer *rocketTimer;
IBOutlet UILabel *rocketCount;
int newTotalSeconds;
int totalRocketSeconds;
int minutes;
int seconds;
}
- (IBAction)Start;
@end
and my .m
#import "FirstViewController.h"
@implementation FirstViewController
- (NSString *)timeFormatted:(int)newTotalSeconds
{
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
return [NSString stringWithFormat:@"%i:%02d"], minutes, seconds;
}
-(IBAction)Start {
newTotalSeconds = 178; //for 2:58
newTotalSeconds = newTotalSeconds-1;
rocketCount.text = [self timeFormatted:newTotalSeconds];
if(timerActive == NO){
timerActive = YES;
newTotalSeconds = 178;
[rocketTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerLoop) userInfo:nil repeats:YES];
}
else{
timerActive = NO;
[r开发者_如何转开发ocketTimer invalidate];
rocketTimer = nil;
}
}
-(void)timerLoop:(id)sender {
totalSeconds = totalSeconds-1;
rocketCount.text = [self timeFormatted:totalSeconds];
}
- (void)dealloc
{
[super dealloc];
[rocketTimer release];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
timerActive = NO;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
@end
There are a few problems with your code!
The bad news is, that none of them relate to the crash you are seeing.
The first and most obvious problem
Actually, you never stop your countdown!
After you've scheduled the timer in Start
, your timerLoop:
-method will be called every second. But you forgot to check whether totalSeconds
has become negative...
The second problem
-(NSString *)timeFormatted:(int)newTotalSeconds
will not work the way you expect it to! Actually, I'm pretty damn sure that Xcode gives you a compiler warning stating "Local declaration of 'newTotalSeconds' hides instance variable".
Try it out: In Start
, replace the line rocketCount.text = [self timeFormatted:newTotalSeconds];
with the line rocketCount.text = [self timeFormatted:42];
and set a breakpoint after it.
The third problem (which actually are a couple of problems in one place)
Your dealloc
is plain wrong:
First and foremost, it's not the best idea to have any calls after [super dealloc]
. Second, "ur doin it wrong": Considering your Start
-method, you don't own the timer so you must not release
it. Instead, if the timer was still valid, you'd need to invalidate
it. But this won't even become a problem, because as long as rocketTimer
is scheduled, your viewController will not be dealloc
ed (unless you have an error within your memory-management elsewhere). I've written a fairly complete example explaining this behavior in an earlier post.
So, what caused the crash?
Honestly:
No clue!
In order to find out what exactly went wrong, try adding a breakpoint to -[NSException raise]
. Alternatively, you can modify the main
function in main.m
to be the following:
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int response;
@try {
response = UIApplicationMain(argc, argv, nil, nil);
} @catch (NSException *e) {
NSLog(@"%@: %@\nCall-stack:\n%@", [e name], [e reason], [e callStackSymbols]);
response = 1;
}
return response;
}
That will tell you in which method your program actually crashed.
Where is rocketTimer
instantiated? You seem to have left that very important detail out. My guess is that rocketTimer
isn't being correctly retained by your code and that is causing your crash when trying to access that object after it has been deallocated.
I'd suggest synthesizing your property and then using the built-in setting by setting self.rocketTimer
when you initialize.
FirstViewController.h
@interface FirstViewController : UIViewController {
NSTimer *rocketTimer;
}
@property (nonatomic, retain) NSTimer *rocketTimer;
- (IBAction)Start;
@end
FirstViewController.m
@implementation FirstViewController
@synthesize rocketTimer;
// test of implementation
// ...
If the problem is that it's not repeating, i'd let the timerLoop method check the value of totalSeconds before substracting. If it's 0, let it set it to 178 again.
If the problem lies somewhere else, please tell us where, and give us a little more information on what the problem is and what you've tried already next time.
精彩评论