I am developing an iPAD application and I want to auto save the contents of the form into SQLITE in every 10 sec intervals. Right now if I press the save button then it saves to the database. Is there any way to auto save the whatever I am writing in the form in every 10-15 seconds. Help me out with this.
Use NSTimer and perform the save every x minutes. The code will look something like this. It is a modified version of the code here.
#interface MyController : UIViewController
{
#private
NSTimer * countdownTimer;
NSUInteger remainingTicks;
}
-(IBAction)doCountdown: (id)sender;
-(void)handleTimerTick;
-(void) saveData;
#end
#implementation MyController
// { your own lifecycle code here.... }
-(IBAction)doCountdown: (id)sender
{
if (countdownTimer)
return;
remainingTicks = 60;
[self saveData];
countdownTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: #selector(handleTimerTick) userInfo: nil repeats: YES];
}
-(void)handleTimerTick
{
remainingTicks--;
[self updateLabel];
if (remainingTicks <= 0) {
[countdownTimer invalidate];
countdownTimer = nil;
}
}
-(void) saveData
{
//Save your data here
}
#end
Related
I am developing a game for class where a timer is ran when a button is pressed.
-(void)setTimer{
self->mTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(buttonNotPushed) userInfo: nil repeats:NO];
}
-(void)resetTimer{
[self->mTimer invalidate];
self->mTimer = nil;
Here is a snippet of how the timer code is used.
- (IBAction)yellowDot1:(id)sender {
if ([_labelColor.text isEqualToString:#"Yellow"]) {
[ self Scoring];
[self label];
[self resetTimer];
[self setTimer];
}
else ([self GameOver]);
}
- (IBAction)redDot1:(id)sender {
if ([_labelColor.text isEqualToString:#"Red"]) {
[ self Scoring];
[self label];
[self resetTimer];
[self setTimer];
}
else ([self GameOver]);
}
The game presents with a Play button which modals over to the next screen. Currently at 5 seconds, I would like to create a "difficult" mode where at the home screen, the user clicks on a "difficult" button and the timer for the game runs at 2 seconds instead. Right now, I am contemplating duplicating my storyboard and view controllers and going that way where I just make the timer a different interval. Is a shorter way possible through code for a difficult mode?
Simply declare a global a variable for this. Use a class (maybe a singleton) that holds the mode and use a -(float) getGameDuration; method
lets say...
// GameHandler.h
static GameHandler *sharedInstance = nil;
#interface GameHandler : NSObject
{
GameMode *mode;
}
typedef enum{
GAMEMODE_EASY = 0,
GAMEMODE_NORMAL,
GAMEMODE_HARD
} GameMode;
-(float) getGameDuration;
implementation
// GameHandler.m
+ (GameHandler *)sharedInstance // implement singleton
{};
-(float) getGameDuration
{
switch(mode)
{
case GAMEMODE_EASY:
return 10.f;
case GAMEMODE_NORMAL:
return 5.f;
case GAMEMODE_HARD:
return 2.f;
}
return 5.f;
}
// your other classes
float gameDurration = [[GameHandler sharedInstance] getGameDuration];
self->mTimer = [NSTimer scheduledTimerWithTimeInterval:gameDurration
target:self
selector:#selector(buttonNotPushed)
userInfo:nil
repeats:NO];
I want to execute some codes with a time sequence like [5s, 10s, 10s, 20s], which means that it executes the code after 5 seconds, and executes it the second time after 10s. I want to use NSTimer, but I can not figure out how can I do.
My method is a bit simpler to implement.
- (void)startExecute
{
intervals=#[#(5),#(10),#(10),#(20)]; // class member
isExecuting=YES; // class member
[self executeTaskAtIndex:0]; // start first task
}
- (void)executeTaskAtIndex:(NSUInteger)index
{
if (index>=intervals.count || !isExecuting) // no intervals left or reset execution
return;
NSNumber *intervalNumber=intervals[index];
NSTimeInterval interval=intervalNumber.doubleValue;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(!isExecuting)
return;
// execute your task here
//...
index++;
[self executeTaskAtIndex:index]; // another iteration
});
}
Create a data structure to hold the time intervals, the target and the action to execute:
(untested)
typedef struct {
NSTimeInterval interval;
id target;
SEL selector;
} ScheduledItem;
Then create an array of these items:
static ScheduledItem _schedule[] = {
{ 5.0, someTarget, #selector(someMethod) },
{ 10.0, someTarget, #selector(someMethod) },
{ 15.0, someTarget, #selector(someMethod) }
};
#define NUM_SCHEDULED_ITEMS (sizeof(schedule) / sizeof(schedule[0]))
and then create a timer somewhere to dispatch the work:
#interface MyClass ()
{
NSTimer *_timer;
unsigned _scheduledItem;
}
- (void)_setupTimer;
- (void)_timerFired:(NSTimer *)timer;
#end
#interface MyClass
- (instancetype)init
{
self = [super init];
if (self) {
_scheduledItem = 0;
[self _setupTimer];
}
return self;
}
- (void)_setupTimer
{
_timer = nil;
if (_scheduledItem < NUM_SCHEDULED_ITEMS) {
NSTimeInterval interval = _schedule[_scheduledItem].interval
_timer = [NSTimer scheduledTimerWithTimeInterval:interval
target:self
selector:#selector(_timerFired:)
userInfo:nil
repeats:NO];
}
}
- (void)_timerFired:(NSTimer *)timer
{
id target = _schedule[_scheduledItem].target;
SEL action = _schedule[_scheduleItem].action;
[target performSelector:action withObject:nil];
_scheduledItem++;
[self _setupTimer];
}
You will most probably have to set-up the _schedule array at runtime, as the target won't be available at compile time. If it's always self then you can leave it out of the schedule altogether and if you always call the same selector then you can leave that out too, leaving just an array of time intervals.
I'm trying to create a simple countdown timer app for myself. So far I've figured out how to create the countdown timers with a stop/reset action on them for a single button I've got attached to the timer.
However, I would like to add multiple timers to the same page and I'm not really sure how to do about making extra calls for the timers. Each of the timers would have it's own number to count down from (7 minutes for one, 3 minutes for the other, etc). These are set intervals that the user is not able to change. Google hasn't really worked out for me on how to do this so I'm hoping someone can at least guide me in the right direction. Below is my code snippets:
ViewController.h
#interface ViewController : UIViewController {
IBOutlet UILabel *firstCountdownLabel;
NSTimer *firstCountdownTimer;
bool timerActive;
int secondsCount;
}
- (IBAction)start:(id)sender;
- (void)timerRun;
#end
ViewController.m
#interface ViewController ()
#end
#implementation ViewController
- (void) timerRun {
secondsCount = secondsCount - 1;
int minutes = secondsCount / 60;
int seconds = secondsCount - (minutes * 60);
NSString *timerOutput = [NSString stringWithFormat:#"%2d:%.2d", minutes, seconds];
firstCountdownLabel.text = timerOutput;
if (secondsCount == 0) {
[firstCountdownTimer invalidate];
firstCountdownTimer = nil;
}
}
//- (void) setTimer {
- (IBAction)start:(id)sender {
secondsCount = 420;
if (timerActive == NO) {
timerActive = YES;
self->firstCountdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerRun) userInfo:nil repeats:YES];
}
else {
timerActive=NO;
[self->firstCountdownTimer invalidate];
self->firstCountdownTimer = nil;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// [self setTimer];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Google doesn't help in showing you how to implement original application ideas.
If you want multiple timers, define multiple timer instance variables:
#interface ViewController : UIViewController
{
IBOutlet UILabel *timer1Label;
IBOutlet UILabel *timer2Label;
IBOutlet UILabel *timer3Label;
NSTimer *timer1;
NSTimer *timer2;
NSTimer *timer3;
int timer1Count;
int timer2Count;
int timer3Count;
bool timer1Active;
bool timer2Active;
bool timer3Active;
}
Then create a separate IBAction for each button that starts each of the timers:
- (IBAction)startTimer1:(id)sender
{
timer1Count = 420;
if (timer1Active == NO)
{
timer1Active = YES;
timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timer1Run:)
userInfo:nil
repeats:YES];
}
else
{
timer1Active=NO;
[timer1 invalidate];
timer1 = nil;
}
}
- (void) timer1Run: (NSTimer*) timer
{
timer1Count -= 1;
int minutes = timer1Count / 60;
int seconds = timer1Count - (minutes * 60);
NSString *timerOutput = [NSString stringWithFormat:#"%2d:%.2d", minutes, seconds];
timer1Label = timerOutput;
if (timer1Count == 0) {
[timer2 invalidate];
timer2 = nil;
}
}
Duplicate the above code for each timer, using "timer2" and "timer3" in place of "timer1". Change the time counts for each one to the desired values. (I changed the names from "firstTimer" to "timer1" because it's easier to edit the code to support multiple timers that way.
I did not write 3 versions of each method for you because you need to figure this out rather than copy & pasting in code that you don't understand.
It would be possible, and require less code, to use the same IBAction method for all your start timer buttons, and have the code check the tag on the button to decide which timer to start.
The code might look like this:
- (IBAction)startTimer1:(id)sender
{
int tag = [sender tag];
switch (tag)
{
case 1: //timer 1
//Put code to start timer 1 here
break;
case 2: //timer 2
//put code to start timer 2 here
break;
}
}
But that might be a bit over your head at the moment.
By the way, forget you ever saw the "self->variable" syntax. it is slower and more error-prone than just referring to the instance variable directly. using object->variable syntax also allows you to access the instance variables of other objects, which is bad practice. You should always use properties to access the instance variables of objects other than yourself.
Also, the timer method should take a single parameter, a timer. I corrected the timer method in the above code.
Create a class as YourTimer with few properties like
NSString *timerLabel;
NSTimer *timer;
NSInteger timerCounter;
Now create an array of YourTimer objects. Then you can access it easily.
This will be modular, maintainable and reusable code, as may be later on you need one more identifier to be with all timers, hence wrap them in one class and use it.
I have an issue at the moment. I am making a game. When two imageViews collide the game will end. I am using CGRECTIntersects rect to detect if the two images collide.
The issue is that when i restart the game the collision will happen when in fact the two images have not actually touched one another?
Any suggestions would be much appreciated.
Thank you
-(void)collision {
if (CGRectIntersectsRect(object.frame, object2.frame)) {
object.hidden=YES;
object2.hidden=YES;
retry.hidden=NO;
[timer invalidate];
}
}
/- (void)viewDidLoad
{
retry.hidden=YES;
timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(object2) userInfo:nil repeats:YES];
objectSpeed1 = CGPointMake(3.0, 2.0);
[super viewDidLoad];
}
/- (IBAction)retry:(id)sender {
[self performSegueWithIdentifier:#"restart" sender:sender];
}
-(void)object2 {
object2.center = CGPointMake(object2.center.x + object2.x, object2.center.y + objectspeed1.y);
if (object2.center.x > 310 || object2.center.x < 10) {
objectspeed1.x = - objectspeed1.x;
}
if (object2.center.y > 558 || object2.center.y < 10) {
objectspeed1.y = - objectspeed1.y;
}
Just consider this case on the code. You can check if image views are on their start position or they came to this position from another. It's enough to keep BOOL property on viewcontroller's class like this:
// ViewController.m
#interface ViewController ()
#property (readonly) BOOL isStarted;
#end
#implementation
- (void)viewDidLoad {
[super viewDidLoad];
_isStarted = NO;
// Make some preparations for app's needs
_isStarted = YES;
}
#end
_isStarted is a flag which shows whether viewcontroller is ready to handle the data.
if(_isStarted) {
// Analyze image views' frame
}
else {
// Do nothing
}
I'm new to programming, and I've been stuck for a while on the following:
When I run the attached code, everything seems to work fine, then the progress bar starts counting up again. The console keeps printing the invalidation confirmation string, but the timer seems to keep rolling. I appreciate your help.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize doneYet;
#synthesize cooking;
#synthesize hidebutton;
- (void)viewDidLoad;
{
[super viewDidLoad];
[doneYet setProgress:doneYet.progress=0.0];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setDoneYet:nil];
[self setHidebutton:nil];
[self setCooking:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
-(void)startTimer
{CurrentTimer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired) userInfo:Nil repeats:YES];}
-(void)timerFired
{ if (doneYet.progress<1) {
[doneYet setProgress:doneYet.progress+0.1];
}
else if (doneYet.progress=1)
{
(void) [CurrentTimer invalidate];
NSLog(#"invalidated CurrentTimer");
hidebutton.hidden = FALSE;
cooking.hidden = TRUE;
[doneYet setProgress:doneYet.progress=0.0];
}
}
- (IBAction)Eggtimer:(id)sender
{
[self startTimer];
hidebutton.hidden = TRUE;
cooking.hidden = FALSE;
;}
#end
This seems a problem
else if (doneYet.progress=1)
for 2 reasons:
the equality comparison operator is == and not = (which is the assign operator)
you are comparing a float number for an exact value, this is never good because floating numbers are not precise, you should check for progress >= 1.0, otherwise you could go over 1.0 (eg 1.0000001) and skip stop condition
In addition in the stop condition you do
[doneYet setProgress:doneYet.progress=0.0];
but formerly it should be
[doneYet setProgress:0.0];
I think you should do this, retain the NSTimer object.
CurrentTimer=[[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired) userInfo:Nil repeats:YES] retain];
One thing you can do is change your startTimer as
-(void)startTimer
{
[CurrentTimer invalidate];
CurrentTimer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired) userInfo:Nil repeats:YES];
}
This will invalidate old timer and there will be only one timer.
My error was in designating the button that commands startTimer as the FirstResponder.
Sorry for using your time and advice on something that was the result of an error not in the code.
Thanks again to everyone who offered their advice. It means a lot to a beginner!