I have been looking for this answer from a while but I could not get find solution. Can any one please tell me how do we calculate time in back ground since user made any interaction with the app. In few websites if you don't interact with the web page for a while you will be logged out. I am looking for this functionality.
I would really appreciate your time.
Thanks
I think you can catch events via a UIApplication custom subclass. You can restart your idle timer there without mucking up all of your code. Here's how to do it:
Make your own UIApplication subclass:
#interface MyUIApplication : UIApplication {
NSTimer *idleTimer;
}
#property(nonatomic,retain) NSTimer *idleTimer;
In your main()
int retVal = UIApplicationMain(argc, argv, #"MyUIApplication", nil);
In your application subclass.m, override sendEvent: and sendAction:. See Apple docs here:
- (void)sendEvent:(UIEvent *)event {
[super sendEvent:event];
[self. idleTimer invalidate];
self. idleTimer = [NSTimer scheduledTimerWithTimeInterval:kIDLE_TIME target:self selector:#selector(logout:) userInfo:nil repeats:NO];}
... same for send action. You can put your logout logic in this class, too:
- (void)logout:(NSTimer *)timer {
// do logout
}
You should still logout (and invalidate the timer) in your app delegate when the app resigns:
- (void)applicationWillResignActive:(UIApplication *)application {
[application logout:nil];
}
You save a UNIX timestamp of the last interaction and then you compare it to a current one. If the difference between them is greater than your time limit, you log user out.
I would log the time when - (void)applicationWillEnterForeground:(UIApplication *)application, and when - (void)applicationWillEnterBackground:(UIApplication *)application, calculate the different, check if it exceed certain value, log off user from previous session.
// Extend method of UIApplication
- (void)sendEvent:(UIEvent *)event {
[super sendEvent:event];
// Only want to reset the timer on a Began touch or an Ended touch, to reduce the number of timer resets.
NSSet *allTouches = [event allTouches];
if ([allTouches count] > 0) {
// allTouches count only ever seems to be 1, so anyObject works here.
UITouchPhase phase = ((UITouch *)[allTouches anyObject]).phase;
if (phase == UITouchPhaseBegan || phase == UITouchPhaseEnded) {
[self resetIdleTimer:NO];
}
}
}
- (void) resetIdleTimer:(BOOL)force {
// Don't bother resetting timer unless it's been at least 5 seconds since the last reset.
// But we need to force a reset if the maxIdleTime value has been changed.
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
if (force || (now - lastTimerReset) > 5.0) {
// DebugLog(#"Reset idle timeout with value %f.", maxIdleTime);
lastTimerReset = now;
// Assume any time value less than one second is zero which means disable the timer.
// Handle values > one second.
if (maxIdleTime > 1.0) {
// If no timer yet, create one
if (idleTimer == nil) {
// Create a new timer and retain it.
idleTimer = [[NSTimer scheduledTimerWithTimeInterval:maxIdleTime target:self selector:#selector(idleTimeExceeded) userInfo:nil repeats:NO] retain];
}
// Otherwise reset the existing timer's "fire date".
else {
[idleTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:maxIdleTime]];
}
}
// If maxIdleTime is zero (or < 1 second), disable any active timer.
else {
if (idleTimer) {
[idleTimer invalidate];
[idleTimer release];
idleTimer = nil;
}
}
}
}
- (void) idleTimeExceeded {
NSLog(#"Idle time limit of %f seconds exceeded -- ending application", maxIdleTime);
// Force application to end
// self.dealloc; -- There's a dealloc in StartProcessViewController.m, but I'm not sure we ought to dealloc the UIApplication object.
_Exit(0);
}
One way to archive this is setting a cookie with a login hash that has an expire time of X minutes every time the user request a page. If the cookie isn't present the user is logged out. This could also be a session cookie. Of course that only works if you're talking about a webapp :)
Related
I am creating a number (~5) NSTimer instances from data stored in a SQLite database using the following code below:
-(void)setupNotificationTimer:(NSDictionary *)timerDetails{
NSLog(#"TIMER REPEATS VALUE: %#", [timerDetails objectForKey:#"repeats"]);
NSLog(#"INTERVAL: %f", [[timerDetails objectForKey:#"interval"] floatValue]);
bool repeat = [[timerDetails objectForKey:#"repeats"] boolValue];
if (repeat) {
NSLog(#"Should Repeat");
}
else{
NSLog(#"Should Not Repeat");
}
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:[[timerDetails objectForKey:#"interval"] floatValue]
target:self
selector:#selector(fireTimer:)
userInfo:timerDetails
repeats:repeat];
[timer fire];
[timers addObject:timer]; //'timers' is a property of the AppDelegate
}
-(void)fireTimer:(NSTimer *)timer {
NSLog(#"Timer Fired");
NSMutableDictionary *dict = [timer userInfo];
[[NSNotificationCenter defaultCenter] postNotificationName:[dict objectForKey:#"notificationName"] object:nil];
}
When I setup these timers the very first time the app loads the timer is setup correctly as the NSLog output below shows but does not repeat despite clearly being set to repeat. Each timer fires once then does not continue.
2013-04-03 11:12:53.541 Test[2635:752b] TIMER REPEATS VALUE: 1
2013-04-03 11:12:53.542 Test[2635:752b] INTERVAL: 10.000000
2013-04-03 11:12:53.543 Test[2635:752b] Should Repeat
2013-04-03 11:12:53.544 Test[2635:752b] Timer Fired
The strange thing happens when I close the app and then re-open it, the timers are created and actually fire repeatedly. This app is also a universal iPhone and iPad app and I only seem to get this behaviour when running the app on iPhone. I really am stumped by this and any help is appreciated.
Edit
As requested the code to cancel the timers:
-(void)viewWillDisappear:(BOOL)animated{
NSArray *viewControllersSet = self.navigationController.viewControllers;
if (viewControllersSet.count > 1 && [viewControllersSet objectAtIndex:viewControllersSet.count-2] == self) {
// View is disappearing because a new view controller was pushed onto the stack
NSLog(#"New view controller was pushed");
} else if ([viewControllersSet indexOfObject:self] == NSNotFound) {
// View is disappearing because it was popped from the stack
NSLog(#"View controller was popped");
for(int i = 0; i < [[appDelegate timers] count]; i ++){
NSTimer *timer = [[appDelegate timers] objectAtIndex:i];
[timer invalidate];
timer = nil;
}
[[appDelegate timers] removeAllObjects];
}
}
If an NSTimer does not fire after being created with scheduledTimerWithTimeInterval, it usually means that it has not been attached to the correct runloop. Could it be that your method setupNotificationTimer() is called with different runloops during initialization and when returning to the foreground? (i.e. in the context of a different thread or similar)
This code would work around the problem:
NSTimer* timer = [NSTimer timerWithTimeInterval:[[timerDetails objectForKey:#"interval"] floatValue]
target:self
selector:#selector(fireTimer:)
userInfo:timerDetails
repeats:repeat];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
This ensures that your timers are scheduled on the main runloop and will fire.
I'm working on a very simple iPhone game that involves choosing the right colored button as many times in a row based on a randomized voice prompt. I have it set up so that if the button is one color and gets clicked, it always goes to a hard-coded color every time (e.g. if you click red, it always turns blue). The color change method is set up in an IBOutlet. I have a timer set up in a while loop, and when the timer ends it checks if the player made the right selection. The problem is that the button color change does not occur until after the timer runs out, and this causes a problem with the method used to check the correct answer. Is there a way to make this color change happen instantly? From what I've searched I know it has something to do with storyboard actions not occurring until after code executes, but I haven't found anything with using a timer. Here is a section of the method that calls the timer if the answer is correct:
BOOL rightChoice = true;
int colorNum;
NSDate *startTime;
NSTimeInterval elapsed;
colorNum = [self randomizeNum:middle];
[self setTextLabel:colorNum];
while (rightChoice){
elapsed = 0.0;
startTime = [NSDate date];
while (elapsed < 2.0){
elapsed = [startTime timeIntervalSinceNow] * -1.0;
NSLog(#"elapsed time%f", elapsed);
}
rightChoice = [self correctChoice:middleStatus :colorNum];
colorNum = [self randomizeNum:middle];
}
One of two things stood out
You're using a while loop as a timer, don't do this - the operation is synchronous.
If this is run on the main thread, and you code doesn't return, your UI will update. The mantra goes: 'when you're not returning you're blocking.'
Cocoa has NSTimer which runs asynchronously - it is ideal here.
So let's get to grips with NSTimer (alternatively you can use GCD and save a queue to an ivar, but NSTimer seems the right way to go).
Make an ivar called timer_:
// Top of the .m file or in the .h
#interface ViewController () {
NSTimer *timer_;
}
#end
Make some start and stop functions. How you call these is up to you.
- (void)startTimer {
// If there's an existing timer, let's cancel it
if (timer_)
[timer_ invalidate];
// Start the timer
timer_ = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(onTimerFinish:)
userInfo:nil
repeats:NO];
}
- (void)onTimerFinish:(id)sender {
NSLog(#"Timer finished!");
// Clean up the timer
[timer_ invalidate];
timer_ = nil;
}
- (void)stopTimer {
if (!timer_)
return;
// Clean up the timer
[timer_ invalidate];
timer_ = nil;
}
And now
Put your timer test code in the onTimerFinish function.
Make an ivar that stores the current choice. Update this ivar when a choice is made and make the relevant changes to the UI. Call stopTimer if the stop condition is met.
In the onTimerFinished you can conditionally call and startTimer again if you desire.
Hope this helps!
first of all thanks for getting into my questions.
now, i tried a lot of different ways to call some function in my code but the ways i find it works (performselector:withobject:afterdelay) are get into the function immediately and i need the function to make some "if's" after random times.
Well you can see the code in here-
-(void)playGame{
isButtonPressed=NO;
int minimum=1;
int maximum=4;
int randomTime=(arc4random()%(maximum-minimum))+minimum;
[self performSelector:#selector(ifButtonNotPressed) withObject:nil afterDelay:randomTime];
}
-(void)closingAction{
NSLog(#"Closing Panel automatic");
if (randomFrog==1){
[self performSelector:#selector(animatePanelCloseAction::) withObject:gameImage1_up withObject:gameImage1_down];
}
[self performSelector:#selector(playGame) withObject:nil afterDelay:0.25];
}
-(IBAction)buttonAction:(id)sender{
if (sender == gameButton1 && randomFrog==1){
[self performSelector:#selector(disableAllButtons)];
score=score+1;
isButtonPressed=YES;
[scoreLabel setText:[NSString stringWithFormat:#"Score:%d",score]];
[self performSelector:#selector(closingAction)];
}
}
-(void)ifButtonNotPressed{
if (isButtonPressed==NO){
[self performSelector:#selector(closingAction)];
}
}
as you can see, im trying to check if button was pressed, but its going inside and check it immeditlly and perform it after delay.
how can i call it after real delay ?!
thank you all.
amir.
Try NSTimer to fix this issue.
if(callTimer)
{
[callTimer invalidate];
callTimer=nil;
}
callTimer=[NSTimer scheduledTimerWithTimeInterval:0.50 target:self selector:#selector(callFunction) userInfo:nil repeats:NO];
with help of this you can call any function at particular time interval. if function call again then it invalidates current timer and create new timer for that.
Dont forgot to invalidate timer after calling function means invalidate timer in particular function.
Hey you can use NSTimer class for the same.
- (void)FireTimer : (NSInteger) afterTimeInterval
{
if (afterTimeInterval > 0) //afterTimeInterval is in seconds
{
[NSTimer scheduledTimerWithTimeInterval: afterTimeInterval
target: self
selector: #selector(ResetListAfterExpiration:)
userInfo: nil
repeats: NO];
}
}
- (void)ResetListAfterExpiration: (NSTimer *)timer
{
// your actions
… … …
[timer invalidate]; // must be done to prevent memory leak
}
//Now You call the FireTimer method from where ever you want and it will wait for afterTimeInterval seconds and call the method ResetListAfterExpiration. That's your answer.
I need to perform certain tasks (many tasks) at different intervals. How can i implement it with single NStimer instance as individual timers will create overhead?
I am doing this exact thing.
in my appdelegate i have a method for the timer and threads (i've removed the threads for simplicity):
-(void)startupThreadsAndTimers{
//updatetime
timer = [NSTimer scheduledTimerWithTimeInterval:(1)
target:self
selector:#selector(updateTime)
userInfo:nil
repeats:YES];
}
and i have a method that the timer triggers
-(void)updateTime{
[[NSNotificationCenter defaultCenter] postNotificationName: #"PULSE" object: nil];
}
in the "awakefromnib" method of the appdelgate class i have this:
[self startupThreads];
Now in the veiwdidload method on the viewcontrollers that need to subscribe to this (to update a clock) i subscribe to the notification centre:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateTimeLeft) name:#"PULSE" object:nil];
And i have a method called "updateTimeLeft"
This works really well but i will revisit it to use threads for a bit of performance at a later time.
To have things trigger at different intervals you could change these selectors to parse a time value and have the subscribing view controllers use a modulus to decide what to do.
i.e.
switch (timerValue % 15){
case 1:
[self someMethod];
break;
case 2:
[self someOtherMethod];
break;
}
Hope this helps :)
You can use NSNotificationCenter to define a notification and at particular time it dispatches a notification so other class can be notified and do some task accordingly...
refer this tutorial...
I had to use this in my iPhone App, this is what I did:
#define kUpdateInterval(x) (iPerformanceTime % x == 0)
int iPerformanceTime;
-(void) mPerformanceGameUpdates {
if (iPerformanceTime == 0) { //Initialization
}
if (kUpdateInterval(1)) { //Every 1sec
}
if (kUpdateInterval(2)) { //Every 2sec
}
if (kUpdateInterval(5)) { //Every 5sec
}
if (kUpdateInterval(10)) { //Every 10sec
}
if (kUpdateInterval(15)) { //Every 15sec
}
if (kUpdateInterval(20)) { //Every 20sec
}
if (kUpdateInterval(25)) { //Every 25sec
}
iPerformanceTime ++;
}
//The method below helps you out a lot because it makes sure that your timer
//doesn't start again when it already has, making it screw up your game intervals
-(void) mPerformanceTmrGameUpdatesLoopShouldRun:(BOOL)bGameUpdatesShouldRun {
if (bGameUpdatesShouldRun == TRUE) {
if (bPerformanceGameUpdatesRunning == FALSE) {
tmrPerformanceGameUpdates = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(mPerformanceGameUpdates) userInfo:nil repeats:YES];
bPerformanceGameUpdatesRunning = TRUE;
}
} else if (bGameUpdatesShouldRun == FALSE) {
if (bPerformanceGameUpdatesRunning == TRUE) {
[tmrPerformanceGameUpdates invalidate];
bPerformanceGameUpdatesRunning = FALSE;
}
}
}
-(void) viewDidLoad {
[self mPerformanceTmrGameUpdatesLoopShouldRun:TRUE];
//TRUE makes it run, FALSE makes it stop
}
Just change the update intervals and you'll be good to go!
Define in app delegate and access it elsewhere using the UIApplication sharedApplication.
Hope this helps
I'm new to iPhone dev, but trying to build a 2D game. I was following a book, but the game loop it created basically said:
function gameLoop
update()
render()
sleep(1/30th second)
gameLoop
The reasoning was that this would run at 30fps. However, this seemed a little mental, because if my frame took 1/30th second, then it would run at 15fps (since it'll spend as much time sleeping as updating).
So, I did some digging and found the CADisplayLink class which would sync calls to my gameLoop function to the refresh rate (or a fraction of it). I can't find many samples of it, so I'm posting here for a code review :-) It seems to work as expected, and it includes passing the elapsed (frame) time into the Update method so my logic can be framerate-independant (however I can't actually find in the docs what CADisplayLink would do if my frame took more than its allowed time to run - I'm hoping it just does its best to catch up, and doesn't crash!).
//
// GameAppDelegate.m
//
// Created by Danny Tuppeny on 10/03/2010.
// Copyright Danny Tuppeny 2010. All rights reserved.
//
#import "GameAppDelegate.h"
#import "GameViewController.h"
#import "GameStates/gsSplash.h"
#implementation GameAppDelegate
#synthesize window;
#synthesize viewController;
- (void) applicationDidFinishLaunching:(UIApplication *)application
{
// Create an instance of the first GameState (Splash Screen)
[self doStateChange:[gsSplash class]];
// Set up the game loop
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(gameLoop)];
[displayLink setFrameInterval:2];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void) gameLoop
{
// Calculate how long has passed since the previous frame
CFTimeInterval currentFrameTime = [displayLink timestamp];
CFTimeInterval elapsed = 0;
// For the first frame, we want to pass 0 (since we haven't elapsed any time), so only
// calculate this in the case where we're not the first frame
if (lastFrameTime != 0)
{
elapsed = currentFrameTime - lastFrameTime;
}
// Keep track of this frames time (so we can calculate this next time)
lastFrameTime = currentFrameTime;
NSLog([NSString stringWithFormat:#"%f", elapsed]);
// Call update, passing the elapsed time in
[((GameState*)viewController.view) Update:elapsed];
}
- (void) doStateChange:(Class)state
{
// Remove the previous GameState
if (viewController.view != nil)
{
[viewController.view removeFromSuperview];
[viewController.view release];
}
// Create the new GameState
viewController.view = [[state alloc] initWithFrame:CGRectMake(0, 0, IPHONE_WIDTH, IPHONE_HEIGHT) andManager:self];
// Now set as visible
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void) dealloc
{
[viewController release];
[window release];
[super dealloc];
}
#end
Any feedback would be appreciated :-)
PS. Bonus points if you can tell me why all the books use "viewController.view" but for everything else seem to use "[object name]" format. Why not [viewController view]?
You have Cocos2D listed as a tag in your question but you're not actually using any Cocos2D code. Have you considered doing a Cocos2D implementation for your games? It will save you some unneeded hassle.
As for your syntax question [myObject view] is used for calling methods on myObject while myObject.view is used for setting/getting instance variables exposed as properties. I don't recall if you can retrieve instance variables using [myObject view] as well but if that works then I guess the only difference between the two is the syntax and you could use both methods to retrieve instance variables.
Hope some of that rambling is useful to you.
From many GL example by Apple, I think you should use a timer.
animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0/60.0)
target:self
selector:#selector(updateAndRender)
userInfo:nil
repeats:TRUE];