Cocoa - Schedule timed tasks to fetch data - ios

recently I am writing an OS X menu bar app that display the current weather info.
I am requesting the data using an external weather API, and suppose I can call a getData() method in my AppDelegate to make a HTTP request and get the data back.
Currently I am using NSTimer but to make the request every 15min in the AppDelegate.swift
NSTimer.scheduledTimerWithTimeInterval(interval, target: self, selector: "getData:", userInfo: nil, repeats: true)
However, now what I want to achieve is to execute this method at a specific time. For example, on an hourly basis everyday - get data on 10:00, 11:00, 12:00, etc...
Can anyone suggest on how to achieve this? Thanks!

This is how you can do this:
var fireDate = NSDate()
var timer = NSTimer(fireDate: fireDate, interval: 60.0, target: self, selector: "getData:", userInfo: nil, repeats: true)
timer.fire()

Related

NSTimer not firing after home button is pressed

II have an NSTimer set to fire each second. Using the Simulator this will call the eachSecond() method correctly after I navigate away from the app by pressing the home button. However, on a real iPhone 6, once I navigate away eachSeconds is not called again until the app is open again.
Why might this behave differently on a real device? Is there anyway to ensure it will fire each second in this use case?
Its a fitness app, so needs to record duration when the phone locks or user navigates away momentarily.
Thanks,
lazy var timer = NSTimer()
fun init() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(RunViewController.eachSecond(_:)), userInfo: nil, repeats: true)
}
func eachSecond() {
// update UI etc.
}
An NSTimer will not fire when your app is suspended. Background execution is different when running under XCode; background execution limits do not apply.
In order to determine how much time has elapsed while your app is suspended, you can store a timestamp in applicationDidEnterBackground and calculate the elapsed time based on the difference between the saved timestamp and current time in applicationWillEnterForeground
You need to add the timer to the main run loop.
func init() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(RunViewController.eachSecond(_:)), userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
}

How to repeat every X seconds in Swift?

I am trying to build a simple single view app which runs an infinite slide show of a selection of images with a time delay between each image change.
The code I wrote for this is below. I tried to put this into viewDidLoad and viewDidAppear but the screen remained blank which I guess is because the function never finishes due to the infinite loop.
I learnt a bit of Python before iOS and with tkinter, your code would go into the mainloop. But I am not quite sure how to do the equivalent in Swift
Could someone please explain why I am having this problem and how to do this in Swift. Thanks.
var arrayimages: [UIImage] = [UIImage(named: "charizard")!,UIImage(named:"Flying_Iron_Man")!]
var x: Int = 0
var images: UIImage
let arraycount = arrayimages.count
repeat{
images = arrayimages[(x % arraycount)]
sleep(1)
slideshow.image = images
x++
} while true
NB: slideshow is an image view outlet.
You're looking for NSTimer
let timer = NSTimer.scheduledTimerWithTimeInterval(
1.0, target: self, selector: Selector("doYourTask"),
userInfo: nil, repeats: true)
The first argument is how frequently you want the timer to fire, the second is what object is going to have the selector that gets called, the third is the selector name, the fourth is any extra information you want to pass as a parameter on the timer object, and the fifth is whether this should repeat.
If you want to stop the code at any future point:
timer.invalidate()
Create a repeating NSTimer:
var timer = NSTimer.scheduledTimerWithTimeInterval(2.0,
target: self,
selector: "animateFunction:",
userInfo: nil,
repeats: true)
Then write a function animateFunction:
func animateFunction(timer: NSTimer)
{
//Display the next image in your array, or loop back to the beginning
}
Edit: Updated for modern Swift versions: (>= Swift 5)
This has changed a lot since I posted this answer. NSTimer is now called Timer in Swift, and the syntax of the scheduledTimer() method has changed. The method signature is now scheduledTimer(timeInterval:target:selector:userInfo:repeats:)
Also, the way you create a selector has changed
So the call would be
var timer = Timer.scheduledTimer(timeInterval: 2.0,
target: self,
selector: #selector(animateFunction(_:)),
userInfo: nil,
repeats: true)
And the animateFunction might look like this:
func animateFunction(timer: Timer)
{
//Display the next image in your array, or loop back to the beginning
}

Incrementally increasing speed of animation by clicks NSTimer, Swift

Hi I'm new to coding and Swift so pardon me if it's a noob question. I'm trying to accelerate the speed of my animation with every click of a button. I tried to do a new variable and dividing it in my button actions but doesn't seem to work. Am I missing something obvious? Thanks for your time!
var animationSpeed:Double = 0.4
timerF = NSTimer.scheduledTimerWithTimeInterval(
animationSpeed, target: self,
selector: "doanimation", userInfo: nil, repeats: true)

In Swift, how to ivalidate NSTimer in AppDelegate when application going background?

I need to translate my iOS application from obj-c to swift. I have a NStimer in ViewController that loads metadata from shoutcast every 30 seconds, but when application resign active it stops, when enter foreground it runs again.
Edit: OK. Problem solved! I added two observers in viewDidLoad with name UIApplicationWillResignActiveNotification and UIApplicationWillEnterForegroundNotification, like below:
override func viewDidLoad() {
NSLog("System Version is \(UIDevice.currentDevice().systemVersion)");
super.viewDidLoad()
self.runTimer()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "invalidateTimer", name: UIApplicationWillResignActiveNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "runTimer", name: UIApplicationWillEnterForegroundNotification, object: nil)
}
and I made two functions. First one for run timer:
func runTimer(){
loadMetadata()
myTimer.invalidate()
NSLog("timer run");
myTimer = NSTimer.scheduledTimerWithTimeInterval(30.0, target: self, selector: "loadMetadata", userInfo: nil, repeats: true)
let mainLoop = NSRunLoop.mainRunLoop()
mainLoop.addTimer(myTimer, forMode: NSDefaultRunLoopMode)
}
and second to stop it:
func invalidateTimer(){
myTimer.invalidate()
NSLog("timer invalidated %u", myTimer);
}
I hope this can help someone. :)
I suggest you use the appropriate system for your task: https://developer.apple.com/library/ios/documentation/iphone/conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW56
Apps that need to check for new content periodically can ask the
system to wake them up so that they can initiate a fetch operation for
that content. To support this mode, enable the Background fetch option
from the Background modes section of the Capabilities tab in your
Xcode project. (You can also enable this support by including the
UIBackgroundModes key with the fetch value in your app’s Info.plist
file.)...
When a good opportunity arises, the system wakes or launches your app
into the background and calls the app delegate’s
application:performFetchWithCompletionHandler: method. Use that method
to check for new content and initiate a download operation if content
is available.

NSTimer 'time' issue

I have an NSTimerand I am using the method scheduledTimerWithTimeInterval but I would like the time interval it takes as a parameter to be a function, not an explicit value. How could I do this?
My code looks like this:
timer = NSTimer.scheduledTimerWithTimeInterval(time(), target: self, selector: "doStuff", userInfo: nil, repeats: true)
The compiler complains with the first parameter time()
edit: the error is "extra argument 'selector' in call"
I'm not sure exactly why you're getting that error, but time() is certainly not what you want for your time interval. That's supposed to be the number of seconds between firings of the timer. For something like a repeating animation timer that will typically be something like 1/30.0 or 1/60.0.
The time function (which, by the way, should take an argument) returns an integer that's the number of seconds since the "epoch." On Mac OS X the epoch is 12:00 AM, UTC of January 1, 2001.
Edit: It sounds from your comment like you've defined your own time function. I would first of all, change the name of your function to (say) timeInterval so it can't possibly collide with the system's time function. And I would make sure your function returns an NSTimeInterval, as opposed to a Float or some other number type, like:
func timeInterval() -> (NSTimeInterval) {
return 1/60.0
}
var timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval(), target: self, selector: "doStuff", userInfo: nil, repeats: true)

Resources