iOS Thread Loop Logic - ios

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 {
...
}

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()
}

How to run NSTimer in background and sleep in iOS?

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
});
}

NSTimer timerWithTimeInterval: not working

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];

How to trigger NSTimer right away?

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) {
}

How do I change timing for NSTimer?

I have the following code:
timer = [[NSTimer scheduledTimerWithTimeInterval:0.50 target:self selector:#selector(onTimer) userInfo:nil repeats:YES] retain];
-(void) onTimer
{
}
After every 0.50 seconds the OnTimer method is called.
But now I want to increment the time-interval.
That means:
OnTimer calls after 0.55
OnTimer calls after 0.60
OnTimer calls after 0.65
OnTimer calls after 0.70
OnTimer calls after 0.75
& so on.
Is there any solution for this?? I have tried lot but its not working.
Sure you can do this. Change repeats:YES to repeats:NO so that the timer doesn't repeat, and then in onTimer, just start a new timer with a longer interval. You need a variable to hold your interval so that you can make it a bit longer each time through onTimer. Also, you probably don't need to retain the timer anymore, as it will only fire once, and when it does, you'll get a new timer.
I'm no Objective-C expert (or iOS expert...) and it's been a while but I think something like this:
float gap = 0.50;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
-(void) onTimer {
gap = gap + .05;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
}
Something like that? Oh, and I'm really not too sure about the retain semantics here... read the docs to make sure you don't leak!
Here is one solution to Hardik's question using NSTimer's fireDate property (written in Swift):
Swift 2
var timeInterval = 0.50
NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("onTimer:"), userInfo: nil, repeats: true)
func onTimer(timer: NSTimer) {
timeInterval += 0.05
timer.fireDate = timer.fireDate.dateByAddingTimeInterval(timeInterval)
}
Swift 3, 4, 5
var timeInterval = 0.50
Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(self.onTimer), userInfo: nil, repeats: true)
#objc func onTimer(timer: Timer) {
timeInterval += 0.05
timer.fireDate = timer.fireDate.addingTimeInterval(timeInterval)
}
You could try adjusting the timer's FireDate, see setFireDate
You can't change the interval at which a timer fires. No way. There's no API for doing this.
Two obvious workarounds: If you always change the interval, then you can just change the next time that the timer fires; this has precedence over the timer interval. Of course you have to do that every time the timer fires. If you sometimes change the interval, just invalidate the first timer and create a new timer with the new interval.
This just work like charm for me.
- (void)FlexibleTimer {
if (!keyTimer) {
keyTimer = [NSTimer scheduledTimerWithTimeInterval:self.intervalOfIdleTimer
target:self
selector:#selector(keyTimerExceeded)
userInfo:nil
repeats:YES];
}
else {
if (fabs([keyTimer.fireDate timeIntervalSinceNow]) < self.intervalOfIdleTimer - 1.0) {
[keyTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:self.intervalOfIdleTimer]];
}
}
}
- (void)keyTimerExceeded {
[self setNextDelayForFlexibleTimer];
[self FlexibleTimer];
NSLog(#"Timer Exceeded %f", [[NSDate date] timeIntervalSince1970]);
}

Resources