Staggering NSTimer Fires - objective-c

I have four NSTimers that work fine. The only problem is that two should fire and then the other two should fire in the middle of the first two. Here is my code:
initTimer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector: #selector(initText) userInfo:nil repeats:YES];
animateTimer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector: #selector(textGlow) userInfo:nil repeats:YES];
initTimer1 = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector: #selector(initText1) userInfo:nil repeats:YES];
animateTimer1 = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector: #selector(textGlow1) userInfo:nil repeats:YES];
The initText and initText1 methods create a UILabel with lazy instantiation and place them on the screen on the same spot. The textGlow and textGlow1 methods animate the text to make it grow bigger and fade away. I want initText1 and textGlow1 to fire in the middle of initText and textGlow. For example, let's say each of these methods takes 2 seconds (I set the animation duration to 2 seconds). I want initText and textGlow to fire, and then one second in, initText1 and textGlow1 to fire.
Thanks. If you need any of my other code to help answer the question, just ask.
----------EDIT-------------
#MDT That worked but there is a problem. What I did was I placed the code above of initTimer1 and animateTimer1 in new functions called initTimer1Wrapper and animateTimer1Wrapper. Then I did your code [self performSelector:#selector(initText1Wrapper) withObject:nil afterDelay:1.0]; and duplicated it but changed the selector to animateText1Wrapper. What happens is initText and textGlow will fire as planned, and then also as planned initTimer1 and animateTimer1 will fire one second in, but what also happens unexpectedly is that initText and textGlow do not finish their remaining one second; the animations just stop. I believe this is because they are UIView animations with [UIView beginAnimation:#"name" context:nil] and [UIView commitAnimations] and more then 1 UIView animations can't run at the same time.
To fix this, should I use Core Animation (which I do not know anything about) or is there another solution? Thanks.
----------EDIT2-------------
Also, just if it is important for you to know, I will dismiss this animation with a UIGestureRecognizer.
Something like:
if(screenIsTapped){
[initTimer invalidate];
[animateTimer invalidate];
[initTimer1 invalidate];
[animateTimer1 invalidate];
}

Try placing something like this inside initText or textGlow.
[self performSelector:#selector(initText1) withObject:nil afterDelay:1.0];

I think you should do this with 2 timers instead of 4. Inside the methods, initText and initText1 just call textGlow and textGlow1, respectively, using performSelector:withObject:afterDelay: with whatever delay you want. And, do you really want these timers to be repeating? Do you want to keep creating new UILabels?

Related

Xcode - NSTimer firing at random intervals? No consistency

So I am using NSTimer to run a function every minute, it fires at the correct time for the first 3 or so attempts and then it suddenly starts firing every second. I have no idea why this is happening? Would anyone be able to let me know as to why NSTimer is firing inconsistently?
Here is the line where I have declared my timer.
[NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:#selector(checkForLocation) userInfo:nil repeats:YES];
It is worth noting that I have NSTimer declared inside of viewDidAppear.
Any help is appreciated,
Thank you.
Try to create a instance for NSTimer by declaring a property. Write a function which will initialize the timer and don’t forget to invalidate it before re-intializing it. Call initializeMyTimer in your -viewDidAppear.
-(void) initializeMyTimer
{
if(myTimer)
{
[myTimer invalidate];
myTimer = nil;
}
myTimer = [NSTimer scheduledTimerWithTimeInterval:60.0f
target:self
selector:#selector(checkForLocation)
userInfo:nil
repeats:YES];
}

Problems with splash screen, segue and timers

I am trying to make a splash screen with timer and segue, that wil be performed after 2 seconds.It is a piece of code frome my SplashScreenClass.m. What is wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(performSegue)
userInfo:nil
repeats:NO];
}
-(void)performSegue{
[self performSegueWithIdentifier:#"splash" sender:self];
In Apple's Human Interface Guidelines, it is recommended that splash screens not be used. Your app could get rejected for this reason.
It's not the best solution to use timer for solving this problem. I recommend performing selector after delay instead. It's quite easier to use. Just put this line in your viewDidLoad method.
[self performSelector:#selector(performSegue) withObject:nil afterDelay:2];

NSEventTrackingRunLoopMode - this runs always?

I've added a timer with the runloopmode NSEventTrackingRunLoopMode like so:
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.50
target:self
selector:#selector(targetMethod:)
userInfo:nil
repeats:YES];
[runLoop addTimer:timer forMode:NSEventTrackingRunLoopMode];
I thought this would only execute whilst for example a menu is open (modal), but it triggers the entire time, even when doing nothing. Is this the normal behavior?
Yes, this is normal behaviour. You add a timer to the runloopMode which is used for tracking events. This runloop runs all the time and is used to determine if there are events that needs to be processed and passed to your event handlers.

iOS5 ARC is it safe to schedule NSTimers from background selectors?

I'm trying to debug my application.
I've been using some NSTimer instances in my non-arc code like this (from the main thread):
[NSTimer scheduledTimerWithTimeInterval:5 target:musicPlayer selector:#selector(playPause:) userInfo:nil repeats:NO];
This works fine if I assign this code to a button and click a button. The timer fires.
I've also tried:
if( self.deliveryTimer == nil)
{
self.deliveryTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(playPause:) userInfo:nil repeats:NO];
}
-(void)playPause:(NSTimer*)timer
{
[deliveryTimer invalidate];
deliveryTimer = nil;
//more code here
}
I would expect the timer to execute, hit the play/pause method below, then turn to nil, so I can reset the timer later. The reason why I'm checking for nil is because I have 3 different code paths that may set the timer. Each one has an NSLog statement indicating that the timer has been scheduled.
My code runs, and I see that the timers are being scheduled, but they don't seem to fire in the course of normal app execution. I'm investigating why. Short term timers, using the same logic fire fine. It is when I let the app run for a while that I'm running into issues.
Could the NSTimers be reclaimed by ARC?
Does it matter if I set the timer from a performSelectorInBackground? As I was writing up this question, I noticed that some of my timers were created from a code path that is being called through:
[self performSelectorInBackground:#selector(notifyDelegateOfDataPoint:) withObject:data];
could the background selector be the reason why my timers do not fire/get reclaimed earlier?
Any help is appreciated, this bug has been bugging me for over 2 weeks!
Update: after changing the code to use the main thread for NSTimers, the timers fire correctly, causing the music to play:
[self performSelectorOnMainThread:#selector(deliverReminder:) withObject:nil waitUntilDone:NO];
-(void)deliverReminder:(id)sender{
[ NSTimer scheduledTimerWithTimeInterval:10 target:reminderDeliverySystem selector:#selector(playAfterDelay:) userInfo:nil repeats:NO];
[self postMessageWithTitle:nil message:#"Deliver Reminder Called" action:kNoContextAction];
}
-(void)playAfterDelay:(id)sender
{
int reminderDelay = reminder.delayValue.intValue;
[playTimers addObject:[NSTimer scheduledTimerWithTimeInterval:reminderDelay target:self selector:#selector(appMusicPlayerPlay:) userInfo:nil repeats:NO]];
}
Here I have a whole bunch of timers, which is because I don't know how to pass a primitive to a target with a selector.
An NSTimer requires a run loop to be running in that background thread for it to keep firing. The main thread already has an active run loop, which is why your timers work fine when executed on it.
If you want to use your timers within a background thread, you can do something like the following:
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
self.deliveryTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(playPause:) userInfo:nil repeats:NO];
[runLoop run];
What was probably happening with your short duration timers firing, but the longer ones not, was that they were firing while the thread was still active, but without a run loop to keep it going, were failing after the thread reached the end of its execution.
I don't believe this is ARC-related, although there may be something there you'll have to watch for, because the NSRunLoop holds on to a timer that is attached to it. Following standard procedure with NSTimers should avoid ARC problems.

Update UILabel by timer doesn't work

I have UIView with Label that shows the time like stopwatch. I set the label from a Timer method. Here is the code below:
ivarTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
My update method looks like this:
- (void)updateTimer {
...
self.myLabel.text = #"someChangedStr";
}
It works great. But on the view I have UITableView and If I scroll the TableView, self.myLabel.text stops update. Should I use threads or something else?
You could run your timer on another thread, but you must always do UI updates on the main thread.
However, try adding your NSTimer to the UITrackingRunLoopMode so it will still fire when tracking touches on your window.
[[NSRunLoop mainRunLoop] addTimer:ivarTimer
forMode:UITrackingRunLoopMode];