Osx/Swift: Call Function at a Specific Date/Time

OSX/Swift: Call function at a specific date/time

You could try Grand Central Dispatch. Specifically use dispatch_walltime() to create a dispatch_time_t representing the time you want the job to run and then use dispatch_after() to submit the job to Grand Central Dispatch for execution at the specified time.

iOS: execute code AFTER a particular date

Your best option is to store it as local data Even though you only want the code to run once, the overhead is so low, the "check" will not impact the speed or feel of the application. Also this will allow you to run additional checks .. If someone deletes the app, for instance, and leaves the local storage behind. If they re-install you could theoretically "remember" that the application has been installed, and said code has already run (until the user clears application data)

Something like:

//Globally set key
struct defaultsKeys {
static let keyDate = "dateKey"
}

// Set the date in local storage
let defaults = UserDefaults.standard
defaults.set("Your Date String", forKey: defaultsKeys.dateKey)

// Get the date from local storage
let defaults = UserDefaults.standard
if let stringDate = defaults.string(forKey: defaultsKeys.dateKey) {
print(stringDate)
// Do your date comparison here
}

Very few lines of code, and even though the check happens every time the application starts .. The overhead is negligible.

Call a function one time per day at a specific time Swift

You cannot guarantee that your app is running at that time, each day. the phone could of lost all of its battery power, app might not be running... etc etc.

But this is just a logical problem... If you want to refresh the data after a certain time each day, you should just store a last refresh time in UserDefaults, and if that time was more than your required expiry time (in this case 24h) then refresh the data and update the last updated time.

So if you have an active user, as soon as the 24 hour time difference expires it would refresh, or if a users phone was off for a few days (for whatever reason) your app would still know it needs to refresh the data once the user comes back to the app.

EDIT: Added code example

class RefreshManager: NSObject {

static let shared = RefreshManager()
private let defaults = UserDefaults.standard
private let defaultsKey = "lastRefresh"
private let calender = Calendar.current

func loadDataIfNeeded(completion: (Bool) -> Void) {

if isRefreshRequired() {
// load the data
defaults.set(Date(), forKey: defaultsKey)
completion(true)
} else {
completion(false)
}
}

private func isRefreshRequired() -> Bool {

guard let lastRefreshDate = defaults.object(forKey: defaultsKey) as? Date else {
return true
}

if let diff = calender.dateComponents([.hour], from: lastRefreshDate, to: Date()).hour, diff > 24 {
return true
} else {
return false
}
}
}

You don't really have to make this a new class or a singleton like I have. It was just easier to keep everything nicely contained for the sake of the answer.

So this will work that if there is no refresh date, or if the number of hours since the last one is greater than 24 then it will update the data and update the last refresh date/time. using the completion it will also return whether it updated data or not.

You could also add a check in here that the current hour of the day is >= 16 if required.

EDIT 2: User selectable hour

private func isRefreshRequired(userPickedHour: Int = 16) -> Bool {

guard let lastRefreshDate = defaults.object(forKey: defaultsKey) as? Date else {
return true
}

if let diff = calender.dateComponents([.hour], from: lastRefreshDate, to: Date()).hour,
let currentHour = calender.dateComponents([.hour], from: Date()).hour,
diff >= 24, userPickedHour <= currentHour {
return true
} else {
return false
}
}

In this modified isRefreshRequired function you can pass a value for the hour and see whether it has been at least 24 hours since the last refresh and that the current hour is or is greater than the users selected hour.

This doesn't mean it will run at say for example exactly 16:00 by the way. it will run when the user loads that screen and the rules pass (min 24 hours passed, currentHour is >= userSelected hour)

EDIT 3: how to call

class ViewController: UIViewController {

let refreshManager = RefreshManager.shared

override func viewDidLoad() {
super.viewDidLoad()

refreshManager.loadDataIfNeeded() { success in
print(success)
}
}
}

EDIT: Changed logic

if let diff = calender.dateComponents([.day], from: lastRefreshDate, to: Date()).day,
let currentHour = calender.dateComponents([.hour], from: Date()).hour,
diff >= 1, userPickedHour <= currentHour {
return true
} else {
return false
}

Recurring function at date/time

This may be pretty heavy to implement (i.e. not straightforward), but if you want a task to run even if your app is terminated, you might need to consider writing your own LaunchAgent.

The trick here would be for the agent to be able to interact with your application (retrieving or sending shared information).

iOS :Call a method in specific time

Actually your code works fine but it needs refreshing ... for example you can use NSTimer
to refresh your method :

[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(updateNewDate) userInfo:nil repeats:YES];

How to get the current time as datetime

Update for Swift 3:

let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)

I do this:

let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: date)
let hour = components.hour
let minutes = components.minute

See the same question in objective-c How do I get hour and minutes from NSDate?

Compared to Nate’s answer, you’ll get numbers with this one, not strings… pick your choice!

Delaying function in swift

You can use GCD (in the example with a 10 second delay):

Swift 2

let triggerTime = (Int64(NSEC_PER_SEC) * 10)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, triggerTime), dispatch_get_main_queue(), { () -> Void in
self.functionToCall()
})

Swift 3 and Swift 4

DispatchQueue.main.asyncAfter(deadline: .now() + 10.0, execute: {
self.functionToCall()
})

Swift 5 or Later

 DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
//call any function
}


Related Topics



Leave a reply



Submit