I'm developing for ios and I'm in the making of a UITextField containing UIDatePicker as its inputView.
My problem is as follows: I have set the minimum time to now --> [NSDate date] and that's because I don't want the user to enter a time that is before now.
This works fine, but if the user stays in the ViewController for when a time passes in the phone, I get a wrong time (1 minute before now).
Is there a way to listen to the hardware clock, and sync with the phone's clock? like listen to the iPhone's (hopefully) notification for changing the minute?I don't want the user to see wrong time, I want the text field to change if the time passes.
I thought of an implementation and I'd like to hear another perspective since mine is not easy at all...
My implementation:
1. run a delayed GCD async for the seconds left in the current minute, and when that reaches, listen for every 60 seconds... but this doesn't seems like the right idea, since if the user leaves the ViewController I might get a leak or user puts the app in the background, it'll be frozen and continue from the wrong place (According to GCD documentation).
Any suggestion will be very appreciated.
Rather than using GDC, take a similar approach but with NSTimer. invalidate the timer when the view is hidden (viewDidDisappear:) and observe app notifications for going to the background and returning to the foreground to reset your timer.
You need to calculate the end of the next minute, this becomes the first fire date (fireDate). Once you have that:
NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate interval:60 target:self selector:#selectior(...) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode: NSDefaultRunLoopMode];
Configure your date picker behind a getter or a method of it's own and do something like this, in the UITextField delegate
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
UIDatePicker *datePicker = self.datePicker;
datePicker.minimumDate = [NSDate date];
textField.inputView = datePicker;
return YES;
}
Related
I'm working on an App where I need to start a timer (using NSTimer) when the Watch is activated. With the Timer I asks some information to the iPhone (about every 1 seconds and maximum for 5 seconds). I'm using this to start the timer
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(myfunction) userInfo:nil repeats:NO];
In the "myfunction" function, I restart the timer for the next time.
- (void) myfunction
{
//Here I update a label text
// [...]
[timer invalidate];
timer = nil;
counter++;
if(counter<5)
{
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(myfunction) userInfo:nil repeats:NO];
}
}
My problem is that in the simulator all works fine but in a real watch (Watch-OS2 GM) the timer sometimes doesn't start or sometimes it starts but only for one time and after seems freeze! I see this because i Update a label in the watch at every elapsed period that shows a counter and I'm sure all is initialized in the "will activate" function. I don't understand why. Someone with the same issue?
From documentation
Use your interface controller’s init and awakeWithContext: methods to
load any required data, set the values for any interface objects, and
prepare your interface to be displayed. Do not use the willActivate to
initialize your interface controller. The willActivate method is
called shortly before your interface is displayed onscreen, so you
should use that method only to make last-minute changes. For example,
you might also use that method to start animations or start other
tasks that should only happen while your interface is onscreen.
So, what method did you use to instantiate timer?
make sure you use willActivate method and also use the didDeactivate method to clean up your interface and put it into a quiescent state. For example, use this method to invalidate timers and stop animations.
Hope this helps
My problem is solved with Watch OS 2.1. The problem was related to a quickly movement of the wrist: with the latest update of WatchOS all the timer are correctly restore after a quick move and all works fine
This question already has answers here:
How do I use NSTimer?
(6 answers)
Closed 8 years ago.
What I am attempting to do is increment a variable every second, minute, etc. that is elapsed when my iOS application is running.
I have looked around and NSTimer seems to be one option, but I'm not sure how to implement it.
So far, all I have is;
NSTimer *time;
And that is only if NSTimer is the most appropriate option to use here.
You have NSTimer *timer; declared alredy, so you need to add the following class method in the any AppDelegate Method, executing which you want to start the timer (Say for example -didFinishLaunchingWithOptions)
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self
selector:#selector(incrementVariable:)
userInfo:nil repeats:YES];
Also, you need to invalidate the timer wherever to want to stop it using:
[timer invalidate];
Now, say you have your Global variable variableName which you want to increment every second. In order to do that, you have to implement the selector you passed in scheduledTimerWithTimeInterval method.
- (void)incrementVariable:(NSTimer *)timer{
variableName++;
}
Hope this helps.
I have some labels on my UI which show something like "2s ago", "1h ago"...
Now I want to update them periodically without user interaction. How could I achieve that?
Use NSTimer. When the screen opens and you display the label, decide when you want it updated next. Say, you just updated the labels saying "2s ago", and the next thing that you want your users to see is "1m ago". You schedule a timer task to fire in 58 seconds, and provide a callback selector that updates the label, and schedules the next firing of the timer.
Since you are likely to update using irregular intervals (60 seconds for the first hour, then 60 minutes for the next 23 hours; one day after that) you should set your timer up without repeating.
Do not forget to cancel the timer when the view disappears.
With NSTimer
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateLabel: userInfo:nil repeats:YES];
And update your label in updateLabel:
Scenario is:
Application has on main run loop that runs every 5 min. When app is backgrounded, the timer is not invalidated.
On foreground after waiting a bit (say 10 min), the timer immediately fires twice. I'm unclear as to what the defined behavior here should be (if any) other than on background, the timer is paused/suspended along with the app.
It seems to me that when the app is foregrounded, the timer actually looks at the elapsed time since background, determines the number of times it should have fired in between, and fires them all. I observed this scenario happening both on iOS 7 simulator and iOS 7 iphone.
Google search didn't turn up much info on this topic. Any ideas/pointers?
Update: Clarification - my question is what is the behavior for NSTimer when the application is backgrounded and then foregrounded again, assuming the timer is not invalidated/nil-ed on background, and a new timer is not created on foreground.
Code sample (code is bit old - pre ARC days):
#implementation ReportHandler {
NSTimer *_reportTimer;
}
- (id)init
{
if (_reportTimer == nil) {
_reportTimer = [[NSTimer timerWithTimeInterval:5*60 target:self selector:#selector(didFireReportTimer:) userInfo:nil repeats:YES] retain];
[[NSRunLoop mainRunLoop] addTimer:_reportTimer forMode:NSDefaultRunLoopMode];
}
}
- (void)didFireReportTimer:(NSTimer *)timer {
// send report over network here, timer is not invalidated here
}
There are no background/foreground handlers either here or in the app delegate dealing with this timer.
It seems to me that when the app is foregrounded, the timer actually looks at the elapsed time since background, determines the number of times it should have fired in between, and fires them all. I observed this scenario happening both on iOS 7 simulator and iOS 7 iphone.
That is a correct description of the behavior of NSTimer and the run loop. When your app is suspended it won't fire (by default, when you background it; but if you start a background task, it will fire as normal while the task is running).
How can I prevent a NSTimer from being delayed by the user scrolling a table?
I found the answer:
I had a timer that repeated about 8 or 9 times with intervals of 0.4 to 0.8 seconds. I don't need much precision, but if the user scrolls a table the timer would stop working until the table finished scrolling (this could be a few seconds wait!). I thought I needed background threads, but timers on background threads were somewhat complicated to implement.
The answer to my problem was very very simple and easy. I just need to add a line after invoking the timer:
//////////// start the timer
self.playingTimer = [NSTimer scheduledTimerWithTimeInterval:tempo target:self selector:#selector(playSoundFromArray:) userInfo:nil repeats:YES];
//////////// the magic line:
[[NSRunLoop currentRunLoop] addTimer:self.playingTimer forMode:UITrackingRunLoopMode];
Now I can scroll the table as much as I want and my timers work OK!!!
Now I need to study a little more NSRunLoop...
You should add your timer for NSDefaultRunLoopMode mode. UITrackingRunLoopMode is used by tracking UI actions(in your case scrolling).