I've created a test application with timer before implementing it in my project.
It was the first time I'm using timer.
But the issue is when I implemented timer using [NSTimer timerWithTimeInterval: target: selector: userInfo: repeats: ]; , it is not working.
Here is my code,
Interface:
#interface uialertViewController : UIViewController
{
NSTimer *timer;
}
-(void)displayAlert;
-(void)hideandview;
#end
Implementation:
#implementation uialertViewController
- (void)viewDidLoad {
[self displayAlert];
[super viewDidLoad];
}
-(void)displayAlert{
timer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(hideandview) userInfo:nil repeats:NO];
alert = [[UIAlertView alloc] initWithTitle:#"testing" message:#"hi hi hi" delegate:nil cancelButtonTitle:#"continue" otherButtonTitles:nil];
[alert show];
[alert release];
alert = nil;
}
-(void)hideandview{
NSLog(#"triggered");
[alert dismissWithClickedButtonIndex:0 animated:YES];
[alert release];
[self displayAlert];
}
#end
Then I Changed [NSTimer timerWithTimeInterval: target: selector: userInfo: repeats: ]; with [NSTimer scheduledTimerWithTimeInterval: target: selector:userInfo: repeats: ]; , It is working. What was the issue with timerWithTimeInterval: ? Am I mising anything in my first implementation ? Thanks in advance.
scheduledTimerWithTimeInterval:invocation:repeats: and scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: create timers that get automatically added to an NSRunLoop, meaning that you don't have to add them yourself. Having them added to an NSRunLoop is what causes them to fire.
With timerWithTimeInterval:invocation:repeats: and timerWithTimeInterval:target:selector:userInfo:repeats:, you have to add the timer to a run loop manually, with code like this:
[[NSRunLoop mainRunLoop] addTimer:repeatingTimer forMode:NSDefaultRunLoopMode];
Other answers on here suggest that you need to call fire yourself. You don't - it will be called as soon as the timer has been put on a run loop.
Also one may want to make sure to add timer on the main thread.
assert(Thread.isMainThread)
let timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(YourSelector), userInfo: nil, repeats: true)
As a previous answer noted schedule on the main thread, but rather than using assert, put it on the main thread:
#objc func update() {
...
}
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
And if async is not desired, try this:
let schedule = {
self.timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
if Thread.isMainThread {
schedule()
}
else {
DispatchQueue.main.sync {
schedule()
}
}
The difference between the two is that the timerWithTimeInterval method returns a NSTimer object that has not yet been fired. To fire the timer you have to use [timer fire]; On the other hand the scheduledTimerWithTimeInterval returns an NSTimer that has already been fired.
So, in your first implementation you were just missing [timer fire];
Related
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()
}
Im a little confused on the logic of creating a loop on a thread that is continuous . Just need a point in the Right Direction.
GCD or NSOpereation?
I have this JSON file that gets updated from a web job every 5 minutes.
Is there a way I can run a thread in the background that constantly checks the JSON for changes every N minutes or seconds ?
I', thinking i could use, just cant figure how I would implement
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC),
I would recommend using NSTimer with repeats: true:
override func viewDidLoad() {
super.viewDidLoad()
let _ = NSTimer.scheduledTimerWithTimeInterval(300, target: self, selector: Selector("checkForJSONChanges"), userInfo: nil, repeats: true)
}
func checkForJSONChanges() {
...
}
Or if you're using Objective-C:
- (void) viewDidLoad {
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:300.0f target:self selector:#selector(checkForJSONChanges) userInfo:nil repeats:YES];
}
- (void) checkForJSONChanges {
...
}
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];
I found a lot of post in stackoverflow about NSTimer run in background.
However I didn't find any solution.
In my app , I play sound in background and I set timer to stop music when it reached that time.
So I need to run my NSTimer background (mean when home button click and sleep iPhone).
How can I do that?
// NSTimer run when app in background <br>
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
loop = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:#selector(Update) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:loop forMode:NSRunLoopCommonModes];
This is what do you want?.
You can’t
Timers only exist within your application. So (except for a very small window) when your app is sent to the background, timers cannot fire anymore.
(The audio keeps running, because it’s played by the system, and not by your app.)
So you cannot use timers for this purpose.
What you can do — as suggested by iPatel — is use a local notification, instead. This will briefly awake your app, allowing you to stop playing the music.
Get Form [This Question] (http://iphonedevsdk.com/forum/iphone-sdk-development/58643-keep-nstimer-running-when-app-is-in-background-multitasking.html)
- (void)btnSetupNotificationClicked:(id)sender
{
UILocalNotification* pOrderCompletedNotification=[[UILocalNotification alloc] init];
if(pOrderCompletedNotification!=nil)
{
[pOrderCompletedNotification setFireDate:[[NSDate alloc] initWithTimeIntervalSinceNow:5.00]];
// [pOrderCompletedNotification setApplicationIconBadgeNumber:1];
[pOrderCompletedNotification setTimeZone:[NSTimeZone systemTimeZone]];
[pOrderCompletedNotification setSoundName:#\"OrderCompleted.m4a\"];
[pOrderCompletedNotification setAlertBody:#\"Order Completed\"];
[pOrderCompletedNotification setAlertAction:nil];
[pOrderCompletedNotification setHasAction:NO];
UIApplication* pApplication=[UIApplication sharedApplication];
if(pApplication!=nil)
{
[pApplication scheduleLocalNotification:pOrderCompletedNotification];
}
else
{
NSLog(#\"Application singleton allocation error.\");
}
[pOrderCompletedNotification release];
[pApplication release];
}
else
{
NSLog(#\"Local notification creation error.\");
} // if
}
With Swift
let app = UIApplication.sharedApplication()
app.beginBackgroundTaskWithExpirationHandler(nil)
let timer = NSTimer.scheduledTimerWithTimeInterval(1,
target: self,
selector:"DoSomethingFunctions",
userInfo: nil,
repeats: true)
NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
I know this post is relatively old but I recently ran into this problem and was having some trouble figuring it out. This is the solution I came up with as of Swift 5. It uses a combination of the RunLoop and Timer classes, with information about them in the provided links below.
Using timers
https://developer.apple.com/documentation/foundation/timer
Using run loops
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW1
https://developer.apple.com/documentation/foundation/runloop
Sample code:
class AMSleepTimerUtil: NSObject {
static let shared = AMSleepTimerUtil()
fileprivate var sleepTimer: Timer?
/// Initialize the timer to trigger a function to execute after a duration of time
/// - Parameter seconds: the time delay until the selector function executes
/// - Returns: true if sleep timer were successfully initialized
func createTimerToStopMusic(at seconds: TimeInterval) -> Bool {
let fireAtDate = Date(timeIntervalSinceNow: seconds)
stopSleepTimer()
self.sleepTimer = Timer(fireAt: fireAtDate,
interval: 0,
target: self,
selector: #selector(pauseMusic),
userInfo: nil,
repeats: false)
guard let sleepTimer = sleepTimer else { return false }
RunLoop.main.add(sleepTimer, forMode: .common)
return true
}
func pauseMusic() {
guard let audioPlayer = AMNowPlayingViewController.sharedInstance()?.audioPlayer else { return }
audioPlayer.pause()
}
/// Used to reset the sleep timer before initializing a new timer if the user clicks the "Set Timer" multiple times
func stopSleepTimer() {
if sleepTimer != nil {
sleepTimer?.invalidate()
sleepTimer = nil
}
}
func sleepTimerIsActive() -> Bool {
return self.sleepTimer != nil
}
}
When you run NSTimer, the #selector method itself will determine wether you want to run in background or main thread.
Initial set up:
self.scanTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(manageMethod) userInfo:nil repeats:YES]; //#property (nonatomic, strong) NSTimer *scanTimer
Case you want to run in Background:
-(void)manageMethod
{
dispatch_queue_t queue = dispatch_queue_create("com.mysite.thread1",NULL);
dispatch_async(queue,^{
//run in background
});
}
I need to call a method when my app starts and then call the same method every 5 seconds.
My code is pretty simple:
// Call the method right away
[self updatestuff:nil]
// Set up a timer so the method is called every 5 seconds
timer = [NSTimer scheduledTimerWithTimeInterval: 5
target: self
selector: #selector(updatestuff:)
userInfo: nil
repeats: YES];
Is there an option for the timer so it's trigger right away and then every 5 seconds ?
NSTimer's -fire, [timer fire]; is what you're looking for.
That will fire/immediately call the timer dismissing the time delay.
You can't schedule the timer and fire the event immediately all in the same line of code. So you have to do it in 2 lines of code.
First, schedule the timer, then immediately call 'fire' on your timer:
timer = [NSTimer scheduledTimerWithTimeInterval: 5
target: self
selector: #selector(updatestuff:)
userInfo: nil
repeats: YES];
[timer fire];
When fire is called, the time interval that your timer waits to fire will reset because it just ran, and then will continue to run thereafter at the designated interval--in this case, every 5 seconds.
In Swift:
timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(foo), userInfo: nil, repeats: true)
timer.fire()
You can initialise the timer and fire it in the same line:
[(checkStatusTimer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:#selector(checkStatusTimerTick:) userInfo:nil repeats:YES]) fire];
In swift this can be achieved in one line like:
Timer.scheduledTimer(withTimeInterval: intervalInSec, repeats: true) {
}