I'm making an application that listening on a UDP socket all the time, even if the application is in the background. when a certain data arrived throw the socket, I want to show the user timer that count 10 seconds from 10 to 0.
is it possible to show this counter while the application is in the background?
can I show the user any message in the background (except [[UIApplication sharedApplication] presentLocalNotificationNow:...] that not good for me), like apple alarm clock?
note
I don't need the application to be approved for app store. I just need it to work at home.
I already successfully keeping the communication in the background and I know that the application running
thanx
You could try using the badge icon, and updating the number from 10 to 0 every second. I'll assume you put these methods in the AppDelegate, but they could go anywhere. Try:
.h
#interface AppDelegate : NSObject <UIApplicationDelegate> {
int _countDownNumber;
NSTimer * _countDownTimer;
}
.m
- (void)updateTimer; {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:_countDownNumber];
_countDownNumber--;
if(_countDownNumber < 0){
[_countDownTimer invalidate];
}
}
- (void)methodThatStartsTheCountDown; {
_countDownNumber = 10;
_countDownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateTimer) userInfo:nil repeats:YES];
}
Hope That Helps!
Related
I have a timer that have to count up to 8 hours (28800 second)
after that it should be released
im wondering how to keep the timer running at the background and/or when application is closed?
this is the NSTimer :
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
and this is my condition :
counter++;
if (counter >= 28800) {
[stopWatchTimer invalidate];
counter =0;
timeLabel.text = #"Time Out";
}
You can't - once your app is closed then it's not running anymore so the timer won't be running either.
Take a look at local notifications?
When application goes in background, In –(void)applicationDidEnterBackground: application delegate method add current counter value and current time in nsuserdefault.
Now when application becomes active before that –(void)applicationWillEnterForeground: will called so in that method get total seconds application was in background ie (current time of application) - (time when application went background which is stored in nsuserdefault) calculate in seconds
so add this also in –(void)applicationWillEnterForeground :
if((seconds calculated) > (28800 - (current counter value stored in nsuserdefault)))
{
// stop timer as it has gone beyond eight hours
}
else
{
// continue task
}
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!
Iam displaying time in my application using NSTimer Class starting with 00:00.00 (mm:ss.SS) when my application launched. I want to terminate my application when time reaches to 75:00.00 (mm:ss.SS) in iPhone.
The below code snippet will do the work for you. But its not recommended to use the exit() method to quit the app as it will appear that the app has been crashed to the end user. I recommend you to show an alert after 75 mins and ask the user to quit the app.
[NSTimer scheduledTimerWithTimeInterval:270000
target:self
selector:#selector(quitTheApp)
userInfo:nil
repeats:NO];
- (void)quitTheApp
{
exit(0);
}
Once you start the timer,immediately next line call the below method:
[self performSelector:#selector(stopTimer) withObject:nil afterDelay:75.0];
And stopTimer method should be like this:
-(void) stopTimer
{
[timer invalidate];
timer = nil;
}
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 :)
I have a view (splash screen) which displays for two minutes:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
[viewController showSplash];
}
- (void)showSplash // Show splash screen
{
UIViewController *modalViewController = [[UIViewController alloc] init];
modalViewController.view = modelView;
[self presentModalViewController:modalViewController animated:NO];
[self performSelector:#selector(hideSplash) withObject:nil afterDelay:120.0];
}
I want to add a timer which counts down from 2 minutes to zero to this splash screen.
I imagine I will need to create another view containing the timer. Is this correct? How would I do this and add it to the splash screen, and how would I make the numbers in the timer be displayed on screen in white?
I know two minutes is a very long time to display a splash screen for... but I am just experimenting with various things, there are other things going on for the two minutes!
Many thanks,
Stu
Edit // Ok I now have this:
(.h)
NSTimer *timer5;
UILabel *countDown;
float timeOnSplash;
(.m)
- (void) updateLabel:(NSTimer*)theTimer
{
float timeOnSplash = timeOnSplash - 1;
countDown.text = [NSString stringWithFormat:#"%02d:%02d", timeOnSplash];
}
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
timer5 = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(updateLabel:)
userInfo:nil
repeats:YES];
countDown.text = [NSString stringWithFormat:#"%02d:%02d", timeOnSplash];
}
I get the following uncaught exception when I run the code:
'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key countDown.'
Any ideas?
Edit 2 // Working now, for an excellent solution see TechZen's answer.
Many thanks to all!
NSTimers are unusual objects in that they don't attach to the object that creates them but to the applications NSRunLoop instances. If a timer is one shot, you don't have to retain any reference to it. You should start the timer and forget about it.
In your case you need two track two time intervals (1) the passing of each second so you can update the interface and (2) passing of the two minute interval total.
For (1) you should evoke a repeating timer of one second interval that calls a method in the modalviewcontroller that updates the interface. The best place to evoke the timer would be in the controlller's viewDidAppear method. For (2) you can have property of the controller that stores a value of 159 and then have the method called by the timer decrement it each time the method is called. When it reaches zero, it invalidates the timer.
You should be aware that timers are affected by how quickly the runloop processes all events. If you have intensive background processes that don't pause every few microseconds, the timer may fail to fire on time. If you run into this problem, you should consider creating a separate threads for the splash screen and the configuration.
I do have to wonder why you need display the splash screen for exactly two minutes.
As an aside, the iPhone Human Interface Guidelines expressly state that you should not use splash screens. They can cause your app to be rejected. Using a splash screen that hangs around to long gives the impression that the app or the phone as failed and Apple doesn't like that either.
If you have some heavy duty configuration to do before the app is usable, it is better to create an interface that shows the configuration in process. That way, it is clear that the app is working and not just hung.
Even better, because no one on the move wants to stare at a static iPhone app for two minutes, it's better to get your user started doing something in one thread while the app configures in another. For example, in some kind of url connection, you could start the user typing in some and address of some data while the app makes the connection. For a game, you could have the user select their user name, review high scores, view instructions etc.
You should remember in the design process that people use apps on the iPhone primarily because it saves them time. They don't have drag out a laptop or go to a computer to perform some task. Your app design should focus on getting the user's task performed as quickly as possible. That is true even in the case of a game.
Normally, I would warn against premature optimization but this is kind of big deal.
Edit01:
You want something like this in your splash screen controller.
#interface SplashScreenViewController : UIViewController {
NSInteger countDown;
IBOutlet UILabel *displayTimeLabel;
}
#property NSInteger countDown;
#property(nonatomic, retain) UILabel *displayTimeLabel;
#end
#import "SplashScreenViewController.h"
#implementation SplashScreenViewController
#synthesize countDown;
#synthesize displayTimeLabel;
-(void) viewDidAppear:(BOOL)animated{
countDown=120;
NSTimer *secTimer=[NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(updateCountDown:) userInfo:nil repeats:YES];
}//------------------------------------viewDidAppear:------------------------------------
-(void) updateCountDown:(NSTimer *) theTimer{
NSInteger mins,secs;
NSString *timeString;
countDown--;
if (countDown>=0) {
mins=countDown/60;
secs=countDown%60;
displayTimeLabel.text=[NSString stringWithFormat:#"%02d:%02d",mins,secs];
} else {
[theTimer invalidate];
// do whatever you wanted to do after two minutes
}
}//-------------------------------------(void) updateCountDown------------------------------------
#end
-------
you can call some method every second with NSTimer. there you can change view of your modal ViewController(for example, change text on the label, which will show time). and when your method will be called for the 120 time, you just invalidate your timer
You can use an NSTimer as #Morion suggested. An alternative is the following:
In your #interface file, add the variable:
NSInteger countDown;
then in #implementation:
- (void)showSplash // Show splash screen
{
UIViewController *modalViewController = [[UIViewController alloc] init];
modalViewController.view = modelView;
[self presentModalViewController:modalViewController animated:NO];
countdown = 120;
[self performSelector:#selector(updateTime) withObject:nil afterDelay:1.0];
}
- (void)updateTime {
//decrement countDown
if(--countDown > 0){
//
// change the text in your UILabel or wherever...
//
//set up another one-second delayed invocation
[self performSelector:#selector(updateTime) withObject:nil afterDelay:1.0];
}else{
// finished
[self hideSplash];
}
}
Yes, one way would be to create a new view which has a transparent background ([UIColor clearColor]) and a label with white text. Just call [modalViewController.view addSubview:timerView] to add it as a subview/overlay.
I'm not sure how much help you need with actually creating the views and setting up the label etc.