Reducing a NSNumber by itself-1, automatically - ios

Ok so basically, I'm trying to build some code that allows an NSNumber to reduce by 1 every minute,
This is what I have so far.
- (void)viewDidLoad {
[super viewDidLoad];
NSNumber *numVar = [NSNumber numberWithUnsignedChar:99];
[self num];
}
-(void)num{
usleep(60000000);
NSNumber *numVar = [NSNumber numberWithUnsignedChar:numVar-1];
[self num];
}
First off, it won't reduce by one every minute and secondly is it wrong to have the initial numVar in viewDidLoad?

We tried this and it worked fine for what we needed :
You need to re-arrange this in your code though
- (void)viewDidLoad{
NSTimer *timer;
int minutes = 0;
//Creating a label that shows the timer ; i assume you have one that is already linked
_labelTimer.text = [NSString stringWithFormat:#"This is %i minute", minutes];
//Creating the timer itself with the NSTimer object
timer = [NSTimer scheduledTimerWithTimeInterval: 60.0 target: self selector:#selector(decreaseTimeCount) userInfo:nil repeats:YES];
//Note that 60 is the number of seconds before it calls the selector. You can use 1 if you want it to change your timer/clock every second
}
- (void)decreaseTimeCount{
//The method changes the value of my variable and updates the label. If i'm at the 10th minute, i could do something, like perform a segue.
minute+=1;
_labTimer.text = [NSString stringWithFormat:#"This is %i minutes", minutes];
if (minutes == 10){
//do stuff
}
}

You sleep inside the main thread, blocking your UI. You need to use an NSTimer or similar timing mechanism to run the function periodically without blocking.

#implementation YourViewController
{
NSNumber *numVar;
}
- (void)viewDidLoad
{
[super viewDidLoad];
numVar = [NSNumber numberWithUnsignedChar:99];
[NSTimer scheduledTimerWithTimeInterval:60 target:self selector:#selector(timerFireMethod:) userInfo:nil repeats:YES];
}
- (void)timerFireMethod:(NSTimer *)timer
{
numVar = [NSNumber numberWithInt:[numVar intValue] - 1];
}

Whenever I need something fast I do it like this
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:#selector(num) withObject:nil afterDelay:60];
}
- (void)num
{
NSNumber *numVar = [NSNumber numberWithUnsignedChar:numVar-1];
[self performSelector:#selector(num) withObject:nil afterDelay:60];
}
And you can decide in the num function wheather you want to do it again after a minute or not.

Related

iOS UISwitch keep sending message every 4 second

I have a chatting app that has a uiswitch. If the Switch button is on, I want the app to send "hi" continuously every 3 seconds even the app is in background mode. I know that I can use NSTimer, but I don't really know how to implement that in this code(This is my first time to develop iOS app). Please help me with this.
My code is :
// Allocate, initialize, and add the automatic button.
_AutomaticSend = [[UISwitch alloc] initWithFrame:CGRectMake([self width] - 50.0, textAreaY + Center(160.0, textAreaHeight), 50.0, 50.0)];
[_AutomaticSend addTarget:self action:#selector(changeSwitch:) forControlEvents:UIControlEventValueChanged];
and
// Switch action
//NSUInteger counter = 0;
- (void)changeSwitch:(id)sender{
if([sender isOn]){
for (int a=1; a<=300; a++)
{
//[self performSelector:#selector(changeSwitch:) withObject:_textField afterDelay:70.0];
[sender setOn:YES animated:YES];
[_textField setText:#"hi"];
NSString * text = [_textField text];
// Update status.
[[TSNAppContext singleton] updateStatus:text];
// Add the status to the bubble.
[self appendLocalPeerTableViewCellWithMessage:text];
}
// NSLog(#"Switch is ON");
} else{
NSLog(#"Switch is OFF");
}
}
Now, the app is showing all "hi" after all 300 "hi" is ready to show. But I want it to send it one by one continuously.
Define a NSTimer instance and a counter in your view controller:
#property (nonatomic, strong) NSTimer *timer;
#property (nonatomic, assign) NSInteger counter;
Implement the method when timer is fired:
- (void)timerAction:(id)sender {
[_textField setText:#"hi"];
NSString * text = [_textField text];
// Update status.
[[TSNAppContext singleton] updateStatus:text];
// Add the status to the bubble.
[self appendLocalPeerTableViewCellWithMessage:text];
// stop the timer after sending for 300 times
self.counter += 1;
if (self.counter >= 300) {
[self.timer invalidate];
self.timer = nil;
}
}
Starts the timer when switch is on:
- (void)changeSwitch:(id)sender{
if ([sender isOn]) {
self.counter = 0;
self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(timerAction:) userInfo:nil repeats:YES];
} else {
// kill the timer when switch is off
[self.timer invalidate];
self.timer = nil;
}
}
However, you can't make the timer to continue working indefinitely after your app is entering background (with some exceptions: VoIP, GPS applications, etc.). Please refer to the official document Background Execution.
//Nstimer *timer in .h
In your UISwitch Method Write like this
- (void)changeSwitch:(id)sender{
if([sender isOn]){
timer=[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(targetMethod)
userInfo:nil
repeats:NO];
}
else
{
[timer invalidate];
}
}
targetMethod Like this
-(void)targetMethod
{
[sender setOn:YES animated:YES];
[_textField setText:#"hi"];
NSString * text = [_textField text];
// Update status.
[[TSNAppContext singleton] updateStatus:text];
// Add the status to the bubble.
[self appendLocalPeerTableViewCellWithMessage:text];
}
Use NSTimer: Documentation of NSTimer
Declare property of NSTimer in .h file:
#property (retain,nonatomic) NSTimer *myTimer;
- (void)changeSwitch:(id)sender
{
if([sender isOn]){
myTimer = [NSTimer scheduledTimerWithTimeInterval: 4 target: self
selector: #selector(AddMessage:) userInfo: nil repeats: YES];
} else{
[self.timer invalidate];
}
}
After each 4 second, timer will call the below function:
-(void) AddMessage:(NSTimer*) timer
{
//Add Message
}

Method being called constantly until the view is dismissed

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.

How can I calculate the instantaneous (or close to) taps per second like cookie clicker does in iOS?

Right now here is the code I'm using. It only updates when the button is pressed and is the average rather than instantaneous.
-(IBAction)button:(id)sender {
[self incrementTapCount];
NSMutableString *aString = [NSMutableString stringWithFormat:#"%.2f", averageTapsPerSecond];
[aString appendFormat:#"%s", " per second"];
current.text = aString;
}
- (void)incrementTapCount
{
tapCountInPastSecond++;
}
- (void)timerActions
{
secondsElapsed = secondsElapsed + .1;
averageTapsPerSecond = (averageTapsPerSecond*(secondsElapsed-.1) +tapCountInPastSecond) / secondsElapsed ;
tapCountInPastSecond = 0;
}
On the view did load...
[NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:#selector(timerActions) userInfo:Nil repeats:YES];
I'm trying to get it to update without pressing the button, and not be the average speed, rather the speed at that moment.
Your timer fires every .1 second and you want to keep a "sliding" total of the taps in the last second. I would suggest an array of 10 integers. Each time the timer ticks you can add the most recent tap count to the end of the array and subtract the oldest.
#property (assign) NSInteger runningTotal;
#property (assign) NSInteger tapsInLastSample;
#property (strong,nonatomic) NSMutableArray *tapHistory;
-(void) viewDidLoad {
[super viewDidLoad];
self.runningTotal=0;
self.tapHistory=[NSMutableArray arrayWithCapacity:11];
[NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:#selector(timerActions) userInfo:Nil repeats:YES];
}
-(IBAction)button:(id)sender {
self.tapsInLastSample++;
}
- (void)timerActions {
self.runningTotal+=self.tapsInLastSample;
[self.tapHistory addObject:[NSNumber numberWithInteger:self.tapsInLastSample]];
if (self.tapHistory.count >10) {
self.runningTotal-=[self.tapHistory[0] integerValue];
[self.tapHistory removeObjectAtIndex:0];
}
current.text=[NSString stringWithFormat:#"Taps in last second=%ld",(long)self.runningTotal];
self.tapsInLastSample=0;
}

NSTimer issue with repeated usage

So I am trying to make a countdown and when its done the game is over. Here is my code:
-(void)Movement667{
loadinglabel.text = [NSString stringWithFormat:#"Go!"];;
end =[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(Movement999)userInfo:nil repeats:YES];
}
-(void)Movement999{
if (gametime > 0){
gametime = gametime - 1;
gametimelabel.text = [NSString stringWithFormat:#"%i", gametime];
}else{
smallrock6.hidden = YES;
endlabel.hidden = NO;
highscore.hidden = NO;
highscoreannouncer.hidden = NO;
highscorebackground.hidden = NO;
highscore.text = [NSString stringWithFormat:#"%i", score];
}
}
The first time I play it everything works fine, and it counts down every second. When I play it a second time and so on it starts off normal then it counts down in greater patterns i.e. 2, 4 , 5 ect. Does anyone know why?
It's because you never stop the timer. So what happens is that when you reset the time and create a new timer there are two timers running at the same time (the selector is called twice per second), then three, four, etc. Try to keep the timer in a property and change the code as follows:
#property (strong, nonatomic) NSTimer *myTimer;//ADDDED
-(void)Movement667{
loadinglabel.text = [NSString stringWithFormat:#"Go!"];;
self.myTimer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(Movement999)userInfo:nil repeats:YES];//CHANGED
}
-(void)Movement999{
if (gametime > 0){
gametime = gametime - 1;
gametimelabel.text = [NSString stringWithFormat:#"%i", gametime];
}else{
[self.myTimer invalidate];//ADDED
smallrock6.hidden = YES;
endlabel.hidden = NO;
highscore.hidden = NO;
highscoreannouncer.hidden = NO;
highscorebackground.hidden = NO;
highscore.text = [NSString stringWithFormat:#"%i", score];
}
}
ADDED: If you need to interrupt your game before you run out of time you should make sure to call [self.myTimer invalidate] in that case as well.
ADDED: If you want to make sure the timer is also invalidated when your ViewController goes off screen I would suggest invalidate the timer in viewDidDisappear:
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.myTimer invalidate];
}
When the game is done, don't forget to invalidate your time with
[end invalidate];
Put this code in the else statement in Movement999.
It stops the receiver from ever firing again. And then you can restart the timer for a new game.

NSTimer automatically increases when I change view controller

In my viewController I inserted a timer for a calculation of numbers taken directly from my database of Parse.com.
The timer is working correctly, were inserted in viewDidAppear and in ViewDidDisappear in such a way as to lock the sequence when changing view controller.
The problem I have is that when I change the view controller with the Push the timer does not stop you give an example:
I open the application and the calculation is done correctly with the animation of NSTimer.
Change View, and then I go back with the back button to view where the timer at this point I see that the numbers contiunano to increase every time I change view and go back ...
Can you explain where I'm wrong?
-(void)viewDidAppear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
[self.navigationController.navigationBar setBackgroundColor:[UIColor clearColor]];
self.title = NSLocalizedString(#"", nil);
[self animatelayertopoint:0];
[self AnimationMenuView:600];
[self QueryForViewPrincipal];
[self QueryForCollectionView];
[self ShowBadgeNumber];
[self Timer];
[collectionView reloadData];
}
-(void)Timer{
timer = [NSTimer scheduledTimerWithTimeInterval:0.012 target:self selector:#selector(CalcoloMediadiLaurea) userInfo:nil repeats:YES];
}
-(void) CalcoloMediadiLaurea{
PFUser *CurrentUser = [PFUser currentUser];
NSNumber *NumeroUndici = [NSNumber numberWithInt:11];
NSNumber *NumeroTre = [NSNumber numberWithInt:3];
NSNumber *ValoreMediaPonderata = [CurrentUser objectForKey:FF_USER_MEDIA_PONDERATA];
int FFValoreTre = [NumeroTre intValue];
int FFValoreUndici = [NumeroUndici intValue];
double MediaPonderata = [ValoreMediaPonderata doubleValue];
double RisultatoMoltiplicazioneValoriPonderataUndici;
RisultatoMoltiplicazioneValoriPonderataUndici = MediaPonderata * FFValoreUndici;
double RisultatoMediaLaurea;
RisultatoMediaLaurea = RisultatoMoltiplicazioneValoriPonderataUndici / FFValoreTre;
CalcoloMediaLaureaLabel.text = [NSString stringWithFormat:#"%.1f", FFTickValoreMediaLaurea ];
FFTickValoreMediaLaurea++;
if(FFTickValoreMediaLaurea > RisultatoMediaLaurea){
[timer invalidate];
timer = nil;
}
}
-(void)viewDidDisappear:(BOOL)animated {
[self animatelayertopoint:0];
[self AnimationMenuView:600];
[self CalcoloMediadiLaurea];
}
The timer get rescheduled again on view did appear without getting invalidated to the previous one.You should make instance of timer in .h and then hold the reference of timer in it .And on view did appear when you are scheduling the timer just invalidate it and then schedule it again.
if([self.timer isValid])
{
[self.timer invalidate];
self.timer=nil;
self.timer=[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(CalcoloMediadiLaurea:) userInfo:nil repeats:YES];
}
This worked for me which is along the lines of the above answer but a little more explicitly stated.
- (void)viewWillAppear:(BOOL)animated
{
NSTimeInterval secondsBetween = [endDate timeIntervalSinceDate:currentTime];
secondsLeft = secondsBetween;
[self countdownTimer];
}
- (void)viewDidDisappear:(BOOL)animated
{
[self.timer invalidate];
self.timer = nil;
}
//Initiates timer
- (void)countdownTimer
{
[self.timer invalidate];
self.timer = nil;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
It's because you are creating new timers without invalidating old ones. The timers don't get invalidated automatically, you have to do it yourself. So if U go on second view and return before your invalidate condition is true you will create new timer and have two of them :)... And so on.

Resources