I have those methods to create a simple countdown in my ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
secondsLeft = 10;
}
- (void)updateCounter:(NSTimer *)theTimer {
if(secondsLeft > 0 ){
secondsLeft -- ;
seconds = (secondsLeft %3600) % 60;
myCounterLabel.text = [NSString stringWithFormat:#"%02d", seconds];
}
else{
secondsLeft = 10;
}
}
-(void)countdownTimer{
secondsLeft = seconds = 0;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
From where I call the method in the subClass :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.vc countdownTimer];
}
So I have a ViewController with a UIView inside. This UIView has a custom class. I want to call from this custom Class a method which is in the ViewController. I achieved to call it but the myCounterLabel.text is logged as (null)... Whereas I call the method from the ViewController itself the myCounterLabel.text is correctly logged with the left seconds. Thanks for your help!
countdownTimer method is in view controller.m file and you calling it from other view controller by making object of ViewController controller but do you notice one thing? When you call countdownTimer method then everytime secondsLeft will be 0 and it set to 10 so whenever you call countdown timer method secondsLeft will be reset.
So timer will not start
Related
I have an endGame view that loads when the user completes a game. It is presented modally over top of the game view. In viewDidLoad I am calling a method to save data such the score and how many of a certain game mode they have played. That method is being called multiple times - about once per second, but it is irregular.
End Game Screen:
#import "endGameScreen.h"
#import "ViewController.h"
#import "GameData.h"
#implementation endGameScreen
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)awakeFromNib {
[self getAchievementData];
}
- (void)getAchievementData {
[RWGameData sharedGameData].timedPlayed++;
NSLog(#"Timed played: %ld", [RWGameData sharedGameData].timedPlayed);
}
- (void)writeAchievementforKey:(NSString *)achKey {
[data setObject:[NSNumber numberWithInteger:1] forKey:achKey];
[data writeToFile: path atomically:YES];
}
I am loading the endGameScreen class like this:
GameViewController.m
- (void)viewDidLoad {
if (self.gameMode == 1) {
self.gridSize = 3;
secondsLeft = 10;
[self countdownTimer];
}
}
-(void)countdownTimer {
secondsLeft = minutes = seconds = 0;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
// Timer in the game going to zero
- (void)updateCounter:(NSTimer *)theTimer {
if (secondsLeft > 0 ){
secondsLeft -- ;
minutes = (secondsLeft % 3600) / 60;
seconds = (secondsLeft %3600) % 60;
timePlayedLabel.text = [NSString stringWithFormat:#"%02d:%02d", minutes, seconds];
if (secondsLeft == 1) {
//Call endGame method
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(endGame)
userInfo:nil
repeats:NO];
}
}
else {
secondsLeft = 10;
}
}
- (void)endGame {
[timer invalidate];
[self saveScores];
//Segue in the storyboard
[self performSegueWithIdentifier:#"endGame" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"endGame"]) {
endGameScreen *vc = [segue destinationViewController];
if (self.gameMode == 1) {
vc.gameMode = 1;
}
else {
vc.gameMode = 2;
}
}
}
I am getting NSLog messages that continually increment saying "Mode One played: 27", "Mode One played: 28", "Mode One played: 29", and so on.
Your -endGame method isn't invalidating the timer you think it is.
-updateCounter: is overwriting your timer instance variable with the new one-shot timer for calling -endGame, but that doesn't stop the other timer, the one created in -countdownTimer. That timer continues to fire, calling -updateCounter:, which keeps creating more one-shot timers to call -endGame. So, that gets called repeatedly.
I have implemented some code that allows a user to set a time limit to countdown from using UIDatePicker, the users then presses a "Start" button and the countdown is printed in to a UILabel.
I am trying to find a way to stop the timer. Here is the code I have so far that starts the timer:
#implementation P11DetailController
int afterRemainder;
int iRemainder;
NSTimeInterval countDownInterval;
- (void)updateCountDown{
afterRemainder --;
int hours = (int)(afterRemainder)/(60*60);
int mins = (int)(((int)afterRemainder/60) - (hours * 60));
int secs = (int)(((int)afterRemainder - (60 * mins) - ( 60*hours*60)));
NSString *displayText = [[NSString alloc] initWithFormat:#"%02u : %02u :
%02u", hours, mins, secs];
self.displayLabel.text = displayText;
}
then when the user user presses "start":
- (IBAction)startButton:(id)sender {
countDownInterval = (NSTimeInterval)_countdownTimer.countDownDuration;
iRemainder = countDownInterval;
afterRemainder = countDownInterval - iRemainder%60;
[NSTimer scheduledTimerWithTimeInterval:1 target:self
selector:#selector(updateCountDown) userInfo:nil repeats:YES];
}
and finally, when the users presses "Stop":
- (IBAction)stopButton:(id)sender {
//not sure what to add here
}
any ideas?
You need to keep a reference to NSTimer as an ivar:
#implementation P11DetailController
{
NSTimer *myTimer;
}
then:
myTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self
selector:#selector(updateCountDown) userInfo:nil repeats:YES];
Then a simple call to:
[myTimer invalidate];
Will stop the timer.
This is all in the documentation which you should consult first.
Thank you in advance.
I am developing a game that runs on a timer. I have a label on the view *countdown. I am using a NSTimer *countdownTimer to run 120 seconds (2:00). That is when the game is over. Also, at the same time...I am running a transition timer that modals to another view controller.
I have it set up where the next view the player can select "Play Again". I have it set up where it goes back to the original view. However, how do I reset the *countdownTimer to run again from 2:00?
- (IBAction)playAgain:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
[self setTimer];
[self GameOver];
[self Score];
[self timerRun];
countdown.text = [NSString stringWithFormat:#"2:00"];
}
This is the button to play again. The countdown text does not reset. Here is my NSTimer for *countdownTimer
-(void) timerRun {
secondsCount = secondsCount - 1;
int minuts = secondsCount / 60;
int seconds = secondsCount - (minuts * 60);
NSString *timerOutput = [NSString stringWithFormat: #"%2d:%.2d", minuts, seconds];
countdown.text = timerOutput;
if (secondsCount == 0) {
[countdownTimer invalidate];
countdownTimer = nil;
}
}
-(void) setTimer {
secondsCount= 120;
countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerRun) userInfo:nil repeats:YES];
When it resets, it just stays at zero instead of going back to 2:00
Thank you for your help.
Sorry this is a repeat question, but I have tried all the solutions I could find without success.
Anyway, here is my problem, specifically. I have the following code where I start a timer on a long press gesture, then stop it when that gesture is cancelled or when the action is complete.
-(void)photoLongPress:(UILongPressGestureRecognizer *)press
{
NSTimer *timer = nil;
if (press.state == UIGestureRecognizerStateBegan)
{
//Start timer
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(photoLongPressTimer:) userInfo:nil repeats:YES];
}
if (press.state == UIGestureRecognizerStateEnded)
{
[timer invalidate];
timer = nil;
}
}
-(void)photoLongPressTimer:(NSTimer *)timer
{
DAProgressOverlayView *progress = (DAProgressOverlayView *)[self.view viewWithTag:kTagPhotoDeleteProgressIndicator];
progress.progress += 0.08;
if (progress.progress == 1)
{
[self deletePhotoSelection];
[timer invalidate];
timer = nil;
}
}
The timer stops when invalidated in the photoLongPressTimer method, but not if the gesture stops in the photoLongPress method. Why might this be? I'm stumped.
Thanks.
You need to store timer in an instance variable so that you can refer to it later. It works in photoLongPressTimer: because the timer is passed as a parameter but in photoLongPress: it is nil because you haven't just created it and it's a local reference.
Add a property:
#property (strong, nonatomic) NSTimer *timer;
Store the new timer into it:
self.timer = [NSTimer schedu...
Invalidate and nil the property:
[self.timer invalidate];
self.timer = nil;
NSTimer *timer = nil;
This line only creates a local variable.
You must make a property for the timer.
Put this in your .h file.
#property (strong) NSTimer *timer;
Then use the code here
-(void)photoLongPress:(UILongPressGestureRecognizer *)press
{
if (press.state == UIGestureRecognizerStateBegan)
{
//Start timer
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(photoLongPressTimer:) userInfo:nil repeats:YES];
}
if (press.state == UIGestureRecognizerStateEnded)
{
[self.timer invalidate];
self.timer = nil;
}
}
-(void)photoLongPressTimer:(NSTimer *)timer
{
DAProgressOverlayView *progress = (DAProgressOverlayView *)[self.view viewWithTag:kTagPhotoDeleteProgressIndicator];
progress.progress += 0.08;
if (progress.progress == 1)
{
[self deletePhotoSelection];
[timer invalidate];
timer = nil;
}
}
Problem is with NSTimer *timer = nil;
in -(void)photoLongPress:(UILongPressGestureRecognizer *)press
method.
remove NSTimer *timer = nil; from this method and store instance of NSTimer.
I'm working on an iOS app where I want to load one view if a UIButton is held for x seconds, another if it's held for x+y seconds, etc. I found a tutorial. The problem I'm running into is, how do I switch the length of the button press? The tutorial switched the number of taps.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
switch ([allTouches count])
{
case 1: // Single touch
{
// Get the first touch.
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
switch ([touch tapCount])
{
case 1: // Single Tap.
{
// Start a timer
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(showAlertView:) userInfo:nil repeats:NO];
[timer retain];
}
break;
case 2: // Double tap.
break;
}
}
break;
case 2: // Double touch
{
}
break;
default:
break;
}
}
Any suggestions?
I got my answer. I just started an NSTimer on a touch down event, and stopped in on touch up inside.
// TRP - On Touch Down event, start the timer
-(IBAction) startTimer
{
self.time = 0;
// TRP - Start a timer
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateTimer) userInfo:nil repeats:YES];
[timer retain]; // TRP - Retain timer so it is not accidentally deallocated
}
// TRP - Method to update the timer display
-(void)updateTimer
{
time++;
NSLog(#"Seconds: %i ", time);
if (15 == self.time)
[timer invalidate];
}
// TRP - On Touch Up Inside event, stop the timer & display results
-(IBAction) btn_MediaMeterResults
{
[timer invalidate];
NSLog(#"time: %i ", self.time);
ResultsViewController *resultsView = [[ResultsViewController alloc] initWithNibName:#"ResultsViewController" bundle:nil];
// TRP - The following line is passing the "time" variable from MediaMasterViewController to ResultsViewController
resultsView.time = self.time;
[self.view addSubview:resultsView.view];
}
Use the UILongPressGestureRecognizer class. Apple has this documented in 3.2 -
http://developer.apple.com/iphone/prerelease/library/documentation/General/Conceptual/iPadProgrammingGuide/GestureSupport/GestureSupport.html#//apple_ref/doc/uid/TP40009370-CH5-SW1