NSTimer Milliseconds countdown - ios

I would like to make a simple countdown with seconds and millisecond: SS:MM.
However, i would like to stop the timer or do something when the timer reach 0:00.
Currently the timer works, but it doesnt stop at 0:00. I can make the seconds stop, but not the milliseconds. What is wrong?
-(void) setTimer {
MySingletonCenter *tmp = [MySingletonCenter sharedSingleton];
tmp.milisecondsCount = 99;
tmp.secondsCount = 2;
tmp.countdownTimerGame = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(timerRun) userInfo:nil repeats:YES];
}
-(void) timerRun {
MySingletonCenter *tmp = [MySingletonCenter sharedSingleton];
tmp.milisecondsCount = tmp.milisecondsCount - 1;
if(tmp.milisecondsCount == 0){
tmp.secondsCount -= 1;
if (tmp.secondsCount == 0){
//Stuff for when the timer reaches 0
//Also, are you sure you want to do [self setTimer] again
//before checking if there are any lives left?
[tmp.countdownTimerGame invalidate];
tmp.countdownTimerGame = nil;
tmp.lives = tmp.lives - 1;
NSString *newLivesOutput = [NSString stringWithFormat:#"%d", tmp.lives];
livesLabel.text = newLivesOutput;
if (tmp.lives == 0) {
[self performSelector:#selector(stopped) withObject:nil];
}
else {[self setTimer]; }
}
else
tmp.milisecondsCount = 99;
}
NSString *timerOutput = [NSString stringWithFormat:#"%2d:%2d", tmp.secondsCount, tmp.milisecondsCount];
timeLabel.text = timerOutput;
}
-(void) stopped {
NSLog(#"Stopped game");
timeLabel.text = #"0:00";
}

Well. You do
tmp.milisecondsCount = tmp.milisecondsCount - 1;
if(tmp.milisecondsCount == 0){
tmp.milisecondsCount = 100;
tmp.secondsCount -= 1;
}
And right after that
if ((tmp.secondsCount == 0) && tmp.milisecondsCount == 0) {
//stuff
}
How could it ever happen that they're both 0 if, as soon as milisecond reaches 0, you reset it to 100?
EDIT: Do instead something like:
if(tmp.milisecondsCount < 0){
tmp.secondsCount -= 1;
if (tmp.secondsCount == 0){
//Stuff for when the timer reaches 0
//Also, are you sure you want to do [self setTimer] again
//before checking if there are any lives left?
}
else
tmp.milisecondsCount = 99;
}

In your code, a first condition is met
if(tmp.milisecondsCount == 0){
tmp.milisecondsCount = 100;
so that the next conditional statment
&& tmp.milisecondsCount == 0
will never be true.

Related

Enabling and diasbling button if statement xcode

I am looking to enable and disable a UIButton in XCode 7 using objective C. This is my code:
- (IBAction)startCount:(UIButton*)sender
{
countInt = 0;
self.Label.text = [NSString stringWithFormat:#"%i", countInt];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countTimer) userInfo:nil repeats:YES];
if (countInt > 0){
sender.enabled = false;
} else {
sender.enabled = true;
}
}
Any idea as to why when I run this, the button doesn't enable and disable when desired?
If you want to disable the button when countInt is greater then 0, you have to move the code that does it to countTimer function.
-(void)countTimer {
if (countInt > 0){
myButton.enabled = false;
} else {
myButton.enabled = true;
}
countInt += 1;
self.Label.text = [NSString stringWithFormat:#"%i", countInt];
}
But there's other ways to do this more efficiently.

How to reset countdown timer in spritekit

How to reset countdown timer when the score is divisible by 10?
Here is the score method
-(void)setScore:(int)score
{
_score = score;
scoreLabel.text = [NSString stringWithFormat:#"Score: %d", score];
}
the update method that counts down time
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
if (startGamePlay) {
startTime = currentTime;
startGamePlay = NO;
}
int countDownInt = 10.0 - (int)(currentTime - startTime);
timeLabel.text = [NSString stringWithFormat:#"%i", countDownInt];
if (self.score % 10 == 0) {
//reset countDownInt here
}
}

Cant get my NSTimer to end when the value <= 0

i cant seem to get my NSTimer to stop when it reaches 0 i've looked around for an answer and i tryed everything please help.
-(void)count {
mainint -= 1;
seconds.text = [NSString stringWithFormat:#"%i", mainint];
}
-(IBAction)start:(id)sender {
play.hidden = YES;
mainint = 60;
timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(count) userInfo:nil repeats:YES];
if (timer1 == 0) {
[timer1 invalidate];
timer1 = nil;
}
}
put your if condition in count() function
-(void)count {
mainint -= 1;
seconds.text = [NSString stringWithFormat:#"%i", mainint];
if (mainint == 0) {
[timer1 invalidate];
}
}
The issue is that your timer will never be nil (0) unless you set it yourself to nil. I think what you're trying to achieve is something like this :
-(void)count {
mainint -= 1;
seconds.text = [NSString stringWithFormat:#"%i", mainint];
if (mainint <= 0) {
[timer1 invalidate];
timer1 = nil;
}
}

iOS app Stopwatch and Timer stop counting when in background

I have an iPhone app which is basically a clock, stopwatch, and timer. Everything works fine, until you leave the app, and the stopwatch and timer stop counting. I think the way to solve this would be to start a counter when the app is put into the background, and add/subtract that from the stopwatch/timer when the app starts up again. Is this the best thing to do, and if so, how would I do this?
UPDATE: The timer, stopwatch, and clock are all in different view controllers. Here is the code for my stopwatch in StopwatchViewController.m:
- (void)stopwatch // Start counting the stopwatch
{
hourInt = [hourLabel.text intValue]; // Store integer values of time
minuteInt = [minuteLabel.text intValue];
secondInt = [secondLabel.text intValue];
if (secondInt == 59) { // Add on one second
secondInt = 0;
if (minuteInt == 59) {
minuteInt = 0;
if (hourInt == 23) {
hourInt = 0;
} else {
hourInt += 1;
}
} else {
minuteInt += 1;
}
} else {
secondInt += 1;
}
NSString *hourString = [NSString stringWithFormat:#"%02d", hourInt]; // Update text to show time
NSString *minuteString = [NSString stringWithFormat:#"%02d", minuteInt];
NSString *secondString = [NSString stringWithFormat:#"%02d", secondInt];
hourLabel.text = hourString;
minuteLabel.text = minuteString;
secondLabel.text = secondString;
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:NO]; // Repeat every second
}
How do I get it to add on the elapsed time the app was in the background?
Add two observers for when app enter in background and for app enterForeGround
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterInBackGround) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterInForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
- (void)applicationWillEnterInBackGround{
// stop your timer here
}
- (void)applicationWillEnterInForeground
{
// start your timer here
}
Example ------
in .h
NSTimer *timer;
float time;
in .m
- (void)viewDidLoad
{
[super viewDidLoad];
timer=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterInBackGround) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterInForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)applicationWillEnterInBackGround
{
[timer invalidate];
}
- (void)applicationWillEnterInForeground
{
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:YES];
}
- (void)stopwatch // Start counting the stopwatch
{
hourInt = [hourLabel.text intValue]; // Store integer values of time
minuteInt = [minuteLabel.text intValue];
secondInt = [secondLabel.text intValue];
if (secondInt == 59) { // Add on one second
secondInt = 0;
if (minuteInt == 59) {
minuteInt = 0;
if (hourInt == 23) {
hourInt = 0;
} else {
hourInt += 1;
}
} else {
minuteInt += 1;
}
} else {
secondInt += 1;
}
NSString *hourString = [NSString stringWithFormat:#"%02d", hourInt]; // Update text to show time
NSString *minuteString = [NSString stringWithFormat:#"%02d", minuteInt];
NSString *secondString = [NSString stringWithFormat:#"%02d", secondInt];
hourLabel.text = hourString;
minuteLabel.text = minuteString;
secondLabel.text = secondString;
}
The easiest way to proceed and save the current time when the application goes to background and then when come back to foreground compute the time interval and add it to your counters, something like:
.. going background ..
NSDate *backgroundTime = [[NSDate date] retain];
.. returning foreground ..
NSTimeInterval elapsed = [NSDate timeIntervalSinceDate:date];
[date release];
yourTimer -= elapsed;
To understand when exactly you should hook these events you should take a look here.

Problems with view controllers going into the background of UITabBarController

I have a UITabBarController with 3 view controllers connected to it. Everything works fine apart from when you switch from one view to another, the new view takes a moment to reload what it was doing. I know this isn't such a big deal but it just makes the app look a bit sloppy. Does anyone know how I can keep the app running in the background, or something so that it doesn't have to reload each time.
As you might have noticed I'm very new to Objective-C so I can understand if I'm being unclear but any help is really appreciated!
EDIT: FOR DAVID
This is the code for the stopwatch in the .m file:
#implementation StopwatchViewController
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
isCounting = false;
}
- (IBAction)startOrStop:(id)sender
{
if (self->isCounting == false) {
self->isCounting = true;
[self startStopwatch];
} else {
self->isCounting = false;
[self stopStopwatch];
}
}
- (void)startStopwatch
{
[startStopButton setTitle:#"STOP" forState:UIControlStateNormal];
[self performSelector:#selector(stopwatch) withObject:self afterDelay:1.0];
}
- (IBAction)resetStopwatch:(id)sender
{
[self reset];
}
- (void)stopwatch
{
if (self->isCounting == false) {
return;
} else {
NSInteger hourInt = [hourLabel.text intValue];
NSInteger minuteInt = [minuteLabel.text intValue];
NSInteger secondInt = [secondLabel.text intValue];
if (secondInt == 59) {
secondInt = 0;
if (minuteInt == 59) {
minuteInt = 0;
if (hourInt == 23) {
hourInt = 0;
} else {
hourInt += 1;
}
} else {
minuteInt += 1;
}
} else {
secondInt += 1;
}
NSString *hourString = [NSString stringWithFormat:#"%02d", hourInt];
NSString *minuteString = [NSString stringWithFormat:#"%02d", minuteInt];
NSString *secondString = [NSString stringWithFormat:#"%02d", secondInt];
hourLabel.text = hourString;
minuteLabel.text = minuteString;
secondLabel.text = secondString;
CGRect hourFrame = self->hourBar.frame;
CGRect minuteFrame = self->minuteBar.frame;
CGRect secondFrame = self->secondBar.frame;
if ((NSInteger)hourFrame.size.height != hourInt) { // check if we need to modify
hourFrame.origin.y -= ((hourInt * 10.0) - hourFrame.size.height);
hourFrame.size.height = (hourInt * 10.0);
self->hourBar.frame = hourFrame;
}
if ((NSInteger)minuteFrame.size.height != minuteInt) { // check if we need to modify
minuteFrame.origin.y -= ((minuteInt * 4.0) - minuteFrame.size.height);
minuteFrame.size.height = (minuteInt * 4.0);
self->minuteBar.frame = minuteFrame;
}
if ((NSInteger)secondFrame.size.height != secondInt) { // check if we need to modify
secondFrame.origin.y -= ((secondInt * 4.0) - secondFrame.size.height);
secondFrame.size.height = (secondInt * 4.0);
self->secondBar.frame = secondFrame;
}
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:NO];
}
}
- (void)stopStopwatch
{
[startStopButton setTitle:#"START" forState:UIControlStateNormal];
}
- (void)reset
{
[startStopButton setTitle:#"START" forState:UIControlStateNormal];
self->isCounting = false;
hourLabel.text = #"00";
minuteLabel.text = #"00";
secondLabel.text = #"00";
CGRect hourFrame = self->hourBar.frame;
CGRect minuteFrame = self->minuteBar.frame;
CGRect secondFrame = self->secondBar.frame;
hourFrame.size.height = 0;
minuteFrame.size.height = 0;
secondFrame.size.height = 0;
hourFrame.origin.y = 321.0;
minuteFrame.origin.y = 321.0;
secondFrame.origin.y = 321.0;
self->hourBar.frame = hourFrame;
self->minuteBar.frame = minuteFrame;
self->secondBar.frame = secondFrame;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
SECOND EDIT FOR DAVID:
Changed the main parts of the code to look like this:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:YES];
[self swapFrames];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[self updateBars];
}
- (void)stopwatch
{
if (self->isCounting == false) {
return;
} else {
hourInt = [hourLabel.text intValue];
minuteInt = [minuteLabel.text intValue];
secondInt = [secondLabel.text intValue];
if (secondInt == 59) {
secondInt = 0;
if (minuteInt == 59) {
minuteInt = 0;
if (hourInt == 23) {
hourInt = 0;
} else {
hourInt += 1;
}
} else {
minuteInt += 1;
}
} else {
secondInt += 1;
}
NSString *hourString = [NSString stringWithFormat:#"%02d", hourInt];
NSString *minuteString = [NSString stringWithFormat:#"%02d", minuteInt];
NSString *secondString = [NSString stringWithFormat:#"%02d", secondInt];
hourLabel.text = hourString;
minuteLabel.text = minuteString;
secondLabel.text = secondString;
[self swapFrames];
[self updateBars];
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:NO];
}
}
- (void)updateBars
{
if ((NSInteger)hourFrame.size.height != hourInt) { // check if we need to modify
hourFrame.origin.y -= ((hourInt * 10.0) - hourFrame.size.height);
hourFrame.size.height = (hourInt * 10.0);
self->hourBar.frame = hourFrame;
}
if ((NSInteger)minuteFrame.size.height != minuteInt) { // check if we need to modify
minuteFrame.origin.y -= ((minuteInt * 4.0) - minuteFrame.size.height);
minuteFrame.size.height = (minuteInt * 4.0);
self->minuteBar.frame = minuteFrame;
}
if ((NSInteger)secondFrame.size.height != (secondInt * 4.0)) { // check if we need to modify
secondFrame.origin.y -= ((secondInt * 4.0) - secondFrame.size.height);
secondFrame.size.height = (secondInt * 4.0);
self->secondBar.frame = secondFrame;
}
}
- (void)swapFrames
{
hourFrame = self->hourBar.frame;
minuteFrame = self->minuteBar.frame;
secondFrame = self->secondBar.frame;
}
I separated the code so that just before the view appear it should update the bars. However, it did not work. I did some investigating by printing out the values of some of the variables at certain points. It appears that in viewWillAppear, secondBar.frame (and minuteBar, etc.) has updated to the correct height. However, in viewDidAppear, that value is reset to 0. This does not happen to secondInt, or secondFrame. Somewhere between those two methods the frame is reset but I cannot figure it out.
From what I understand, the frames for your properties self.hourBar, self.minuteBar and self.secondBar are set to 0 when you switch between tabs, and only update them every second.
If this is indeed the case, just set them to their correct values in your viewControllers viewWillAppear: method (assign them to some property in viewWillDisappear:).
As a sidenote, you seem to be coming from C++. The "->" notation is very uncommon for Objective-C, since properties are accessed with ".", and their corresponding instance variable with "->". Using the arrow notation will not call the auto-synthesised getter/setter methods of properties!
Also, is there a specific reason why you always create new NSTimer objects instead of setting repeats: to yes? Creating a timer and adding it to a runloop (which scheduledTimerWith:... does) is a relatively costly operation.

Resources