NSTimer not invalidated even if cancelled in iPad arc project - ios

I am activating timer to call a webservice api to sync with details.After fetching a details of the user,i am activating this timer.i call activateSyncTimer where itself i am cancelling if previous activated timer.Also in the viewwilldisappear i call clearSyncTimer .But in console i see that the timer is not invalidated.I am using ipad and the project is arc fied
- (void)activateSyncTimer {
[self clearSyncTimer];
if (self.canTakeTest && [[NSUserDefaults standardUserDefaults] boolForKey:kIsLoggedIn]) {
self.syncTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(syncTestWithServer) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.syncTimer forMode:NSDefaultRunLoopMode];
}
}
- (void)clearSyncTimer {
if (self.syncTimer != nil) {
[self.syncTimer invalidate];
self.syncTimer = nil;
}
}

Try removing this line
[[NSRunLoop mainRunLoop] addTimer:self.syncTimer forMode:NSDefaultRunLoopMode];
You don't have to add the timer to the runloop manually if you call the method scheduledTimerWithTimeInterval: target: selector: userInfo: repeats:

Related

How to create a timer to reload a tableView on a fixed interval?

for a school project we need to create a application which refreshes its content on a fixed interval. The content is in a collectionView. The interval is once every 40 seconds. What would be the best approach to achieve this?
Try the following :
NSTimer *aTimer = [NSTimer scheduledTimerWithTimeInterval:40 target:self selector:#selector(yourMethod) userInfo:nil repeats:YES];
yourMethod func
-(void)yourMethod{
[self.yourCollectionView reloadData];
}
When you don't want to timer, stop the timer using invalidate.
[aTimer invalidate];
aTimer = nil;
Hope it helps..
Use the code below
NSTimer *current_timer = [NSTimer timerWithTimeInterval:10.0 target:self selector:#selector(updateDefaultTimer:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:current_timer forMode:NSDefaultRunLoopMode];
- (void) updateDefaultTimer:(NSTimer *)timer{
[self.yourCollectionView reloadData];
}
updateDefaultTimer will call every 10 sec
You can create repeated timer and reload your collection in its function.
var timer: NSTimer!
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(40.0, target: self, selector: #selector(reloadCollection), userInfo: nil, repeats: true)
}
func reloadCollection() {
// your code here
// ...
collectionView.reloadData()
}

NSTimer inside global queue is not called when the app is in the background

I want to run a selector using NSTimer which contains some network calls and some other tasks. I want to do that on global queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSTimer * myTimer=[[NSTimer alloc]init];
myTimer = [NSTimer timerWithTimeInterval:10*60 target:self selector:#selector(syncGroupAutomatically) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
});
-(void)syncGroupAutomatically
{
NSLog(#"Some Network calls and some other things\n");
}
If I run this code, it works fine when app is in foreground, but as soon as I press the home button it stops calling the syncGroupAutomatically method.
If anybody having any idea how to run this NSTimer even when app is in the background. Please help me.

invalidate NSTimer inside dispatch_async

I am creating a game, and inside the game I need to get a time counter.
I works great but when I scroll the map it stops and then when I finish scrolling it start again. I fix this with dispatch_async. Here is the code
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timeNext) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
Timer:
__block NSTimer *timer;
But if the app goes to the background I need to stop this times (and when it get active it starts again).
With this way I can scroll the map and the timer works well I try:
- (void)timeNext {
[timer invalidate];
}
and didin't work. Anyone knows how to stop it? or any other idea to accomplish this task?
Don't create your timer on a global queue's thread and then start a run loop on that thread.
Just create your timer on the main thread (main run loop), and add it to the tracking run loop mode. A timer can be added to multiple run loop modes.
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timeNext) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
If you're using UIScrollView to scroll via your game world, timer will be paused while scroll is tracking touches - you need to setup timer to use it with different mode - UITrackingRunLoopMode, e.g.
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
instead of
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
This will allow your timer to fire events while controls such as scroll is tracking user's touches.
[EDIT]
You create timer e.g. via
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
then add this timer to runloop (basically, you should add it to your app main runloop):
NSTimer* timer = [NSTimer timerWithTimeInterval:1./60. target:self selector:#selector(tick) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
I use NSRunLoopCommonModes instead of UITrackingRunLoopMode, everythings looks fine. The main thread ui operation will not block tick function anymore.
NSTimer* timer = [NSTimer timerWithTimeInterval:1./60. target:self selector:#selector(tick) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

NSTimer not calling Method [duplicate]

This question already has answers here:
NSTimer timerWithTimeInterval: not working
(4 answers)
Closed 9 years ago.
I have an NSTimer that should call a method every second, but it doesn't seem to be calling it at all.
This is how I declare the timer:
[NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(fadeManager:) userInfo:nil repeats:YES];
This is the method it calls:
-(void) fadeManager: (NSTimer*) timer{
NSLog(#"IT'S WORKING!");
self.playHead += .1; // keeps track of where they are in full track
if (self.playHead >= self.wait && ![player isPlaying]) { // checks if wait is over
[player play];
}
if (self.playHead >= self.duration + self.startTime && [player isPlaying]) { // checks if full duration is over
[player pause];
[self reset];
}
int fadeOutArea = self.startTime + self.duration - self.fadeOut;
int fadeInArea = self.startTime + self.fadeIn;
if (self.playHead <= fadeInArea && [player volume] < relativeVolume) { // checks if fadingIn.
[self fadeInIncriment];
}
if (self.playHead >= fadeOutArea && [player volume] > 0) {
[self fadeOutIncriment];
}
}
The code was not working so I put the NSLog in as well as a break point. It seems that it is never being called. Why is this? Does it matter that I declared the method in the .m file like this:
#import <AVFoundation/AVFoundation.h>
#interface CueMusic ()
- (void) delayFadeOut: (AVAudioPlayer*) dFade;
- (void) fadeInIncriment;
- (void) fadeOutIncriment;
- (void) fadeManager: (NSTimer*) timer; // <--------
- (void) start;
#end
#implementation CueMusic
.......
Either use
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(fadeManager:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
or
//schedules the timer
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(fadeManager:) userInfo:nil repeats:YES];
From the docs Scheduling Timers in Run Loops
Use the scheduledTimerWithTimeInterval:invocation:repeats: or scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: class method to create the timer and schedule it on the current run loop in the default mode.
Use the timerWithTimeInterval:invocation:repeats: or timerWithTimeInterval:target:selector:userInfo:repeats: class method to create the timer object without scheduling it on a run loop. (After creating it, you must add the timer to a run loop manually by calling the addTimer:forMode: method of the corresponding NSRunLoop object.)
Swift Code
Either
let timer: NSTimer = NSTimer(timeInterval: 1.0, target: self, selector: "fadeManager:", userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
Or
//schedules the timer
NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "fadeManager:", userInfo: nil, repeats: true)
Your problem is that when using timerWithTimeInterval:target:selector:userInfo:repeats:, the resulting timer does not automatically get added to the run loop. I would recommend using scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: instead, which performs this step for you.
If you prefer to use timerWithTimeInterval:target:selector:userInfo:repeats: then you need to manually add the timer to the current run loop. To do this, call NSRunLoop's addTimer:forMode: method. Documentation
[[NSRunLoop currentRunLoop] addTimer:tTimer forMode: NSDefaultRunLoopMode];
You need to fire the timer.
You can do it by adding it to a thread:
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(fadeManager:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
or calling
[timer fire];
You can use:
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

NSTimer not firing the selector

In ios5.0 with ARC, in my rootviewcontroller I call a method in a security manager object that is held by the app delegate. In that method I setup the timer as below
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self
selector:#selector(updateModel:) userInfo:str repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
However, this never fires the selector ie. updateModel: never gets called. What may be wrong? Is there another more efficient way I can do this without using NStimer?
Could also be a threading problem:
if
[NSThread isMainThread]
is false then start the timer like this:
dispatch_async(dispatch_get_main_queue(), ^{
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(tick:) userInfo:nil repeats:YES];
})
You seem to be a bit mixed up with your timer variable.
You initialize a new timer but you aren't actually using it. Do you want to use the timer you initialized or do you want to you ApplicationDelegate.timer?
Here are the two possible solutions.
Option One (assuming that you have a class instance titled ApplicationDelegate and that it has a timer property):
ApplicationDelegate.timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(updateModel:) userInfo:str repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:ApplicationDelegate.timer forMode:NSRunLoopCommonModes];
Option Two:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(updateModel:) userInfo:str repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
I catch the same issue and I fire timer in main queue to solve it:
[NSURLConnection sendAsynchronousRequest:request queue:_operationQueue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
[self loopUpUpdateStart];
}];
-(void)loopUpUpdateStart{
dispatch_async(dispatch_get_main_queue(), ^{
_loopTimerForUpRevision =
NSTimer scheduledTimerWithTimeInterval: kNetworkLoopIntervalUpRev
target: self
selector: #selector(myCoolMethod)
userInfo: nil
repeats: YES];
TRACE(#"Start Up updates");
});
}
This line has several problems:
[[NSRunLoop currentRunLoop] addTimer:ApplicationDelegate.timer forMode:NSRunLoopCommonModes];
First, it should not be required at all. -scheduledTimerWithTimeInterval:... already adds the timer to the runloop. You do not need to add it again.
Second, the local variable timer is unrelated to the property ApplicationDelegate.timer (which is presumably nil at this point).
If you're talking to the application delegate so much that you've created something called ApplicationDelegate (a global? a macro?), you're talking to it too much. The application delegate is the delegate for the application; it assists in the application starting and stopping and responding to system events. The application delegate is not a place to store global variables. A timer is definitely not the kind of thing you'd fetch from another object in any case.

Resources