Watch OS2 NSTimer problems - ios

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

Related

Scheduled NSTimer's selector called with delay in iOS

I have an NSTimer that should be running all the time the app is active. It is intended to show a countdown that depends on certain user's actions. I fire this timer this way:
self.timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(notifyTimerTick:)
userInfo:nil
repeats:YES];
Then, in the method notifyTimerTick:, I update the countdown label I show to users and, if the countdown is over, I invalidate the timer, I look for a new countdown, and I fire the timer again.
I'm not having troubles being the UI blocked doing this way, but on the other hand, I've found that sometimes the notifyTimerTick: selector call is significantly delayed: I have a view that takes a couple of seconds to be completely loaded, and I've seen that timer's selector is not called until the corresponding view controller's viewDidLoad delegate method is called.
I've read several posts dealing with timers blocking the UI, but I'm not sure how to deal with a timer getting blocked by the UI... what the best way to handle this should be?
Thanks in advance
You need to use a different run loop mode.
When you use the ScheduledtimerWithTimeInterval class method, the timer is scheduled on the current run loop.
Instead do something like this:
NSTimer *labelTick = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:labelTick forMode:NSRunLoopCommonModes];

How to manage memory effectivily in ios

I have created a view in which background is changing randomly.A total of 10 images .that i am using for displaying .
Below is the code for Background images.
- (void)viewWillAppear:(BOOL)animated
{
myTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(changeImage) userInfo:nil repeats:YES];
}
-(void)changeImage
{
self.imgView.image=nil;
int randNum = rand() % (9 - 1) + 1;.
NSString *num = [NSString stringWithFormat:#"%d", randNum];
self.imgView.image=[UIImage imageNamed:[NSString stringWithFormat:#"%#.png",num]];
}
Code is working fine .
My question is;its showing over 34mb memory usage ,when i push other view it's still over 34 mb.although i have make the myTimer variable nil;
- (void)viewWillDisappear:(BOOL)animated
{
[myTimer invalidate];
self.imgView.image=nil;
myTimer = Nil;
}
How can i manage memory usage here?
You have to invalidate your timer, setting it to nil will not prevent it from firing:
Once scheduled on a run loop, the timer fires at the specified interval until it is invalidated. A non-repeating timer invalidates itself immediately after it fires. However, for a repeating timer, you must invalidate the timer object yourself by calling its invalidate method. Calling this method requests the removal of the timer from the current run loop; as a result, you should always call the invalidate method from the same thread on which the timer was installed. Invalidating the timer immediately disables it so that it no longer affects the run loop. The run loop then removes the timer (and the strong reference it had to the timer), either just before the invalidate method returns or at some later point. Once invalidated, timer objects cannot be reused.
So you need
[myTimer invalidate];
myTimer = nil;
To stop it running.
In terms of the memory use; what are you expecting to happen? If you've just pushed a new view on the navigation stack the old view is still around and its contents will be in memory. The layer cache won't be removed until the app comes under memory pressure, and 34MB probably isn't going to cause that.
As pointed out in comments, imageNamed caches images in memory (again, until you come under memory pressure) and you also need to call the super implementations of viewXXappear to make sure UIKit is handling things properly.
Try simulating a memory warning and seeing what happens. I don't think you've got anything to worry about, now you're invalidating the timer.
Also try adding to viewdiddisappear,
self.imgView=nil;
The method imageNamed: caches the image it only evict it during memory pressure situations, try to use imageWithContentsOfFile: and when you want to force a release set the image property of the image view to nil.

NSTimer behavior on background/foreground

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).

NSTimer not stopping after the app goes into background

Until yesterday I was sure, the NSTimer will get stopped after the app goes into background. I'm have a feeling like experiencing some anomally.
My app has update location and play audio background modes. Update location is refreshed every few seconds. But it only happends on one of the app screens. There also is NSTimer refreshing some UI.
I've scheduled it like this:
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime) userInfo:nil repeats:YES];
There is also a method, which content is irrelevant now:
-(void)updateTime
{
//irrelevant content, but the method gets fired even when the app is in background
}
The weird thing is, thah the method, which is only fired by the NSTimer and nowehere else is fired even after the ap go into the background. What is happening here? Is that normal behaviour?
Because you are using background modes with location and audio your app is still alive in background.and so your timers are running.
If you remove background modes with location and audio that you are using and then try the timers wont work.
Its Normal behaviour. Correct me if i'm wrong.
Create your timer as public i mean add it in .h file and access it when your app. enter in backGround Mode
- (void)applicationDidEnterBackground:(UIApplication *)application
By above method and set your timer as inValidate.. its fix.
And if you want to do again start your timer then you can access it by
- (void)applicationWillEnterForeground:(UIApplication *)application
this method. Here you need to recreate your timer.
You can stop the timer using invalidate the timer.
[self.timer invalidate];
self.timer= nil;

how to prevent an NSTimer to be delayed or interrupted by user interface actions in iOS 5

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).

Resources