I have an array of activities that need to be run at a specific time. The run in a background helper app. The array is sorted on date/time.
At 12:08:51 I add a new item in the array.. to run at 12:12. Upon creation the array is sorted again and the closest is added as an activity to a NSBackgroundActivityScheduler.
However it runs at creation and a few times more before 12:12. The next automation Normal doesn't run at creation as activity (activity Normal is already in the array of activities).
Why is this happening? And how can I fix it?
Log:
Code:
At 12:08:51 I add a new item in the array.. to run at 12:12. Upon creation the array is sorted again and the closest is added as an activity to a NSBackgroundActivityScheduler.
However it runs at creation and a few times more before 12:12. The next automation Normal doesn't run at creation as activity (activity Normal is already in the array of activities).
Why is this happening? And how can I fix it?
Log:
Code Block 12:08:34.272494+0200 Started Automation Activity 12:08:34.276633+0200 Next Automation Normal on 2021-04-15 08:50:00 +0000 12:08:51.550121+0200 Started Automation Activity 12:08:51.554565+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000 12:08:51.755904+0200 Automation Test1212 is running 12:08:51.756135+0200 Changing to ID DFA4B3D5-3D6C-4F47-A740-7F8C2D6FB30D 12:08:57.040569+0200 Prepare for next automation 12:08:57.040641+0200 Stopped Automation Activity 12:08:57.040829+0200 Started Automation Activity 12:08:57.047549+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000 12:09:04.400019+0200 Started Automation Activity 12:09:04.404916+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000 12:10:29.600003+0200 Automation Test1212 is running 12:10:29.600073+0200 Changing to ID DFA4B3D5-3D6C-4F47-A740-7F8C2D6FB30D 12:10:35.269521+0200 Prepare for next automation 12:10:35.269598+0200 Stopped Automation Activity 12:10:35.269763+0200 Started Automation Activity 12:10:35.275532+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000 12:11:20.557440+0200 Automation Test1212 is running 12:11:20.557496+0200 Changing to ID DFA4B3D5-3D6C-4F47-A740-7F8C2D6FB30D 12:11:26.154006+0200 Prepare for next automation 12:11:26.154087+0200 Stopped Automation Activity 12:11:26.154256+0200 Started Automation Activity 12:11:26.161030+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000 12:12:10.062696+0200 Automation Test1212 is running 12:12:10.062803+0200 Changing to RuleSetID DFA4B3D5-3D6C-4F47-A740-7F8C2D6FB30D 12:12:15.658318+0200 Prepare for next automation 12:12:15.658471+0200 Stopped Automation Activity 12:12:15.658667+0200 Started Automation Activity 12:12:15.664819+0200 Next Automation Normal on 2021-04-15 08:50:00 +0000
Code:
Code Block func nextAutomationFireDate() { let moc = CoreDataStorage.shared.persistentContainer.viewContext let automationDataRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "AutomationDB") do { var automations: [AutomationDB] = [] automations.removeAll() // swiftlint:disable force_cast automations = try moc.fetch(automationDataRequest) as! [AutomationDB] let now = Date() var automationItems: [AutomationStruct] = [] automationItems.removeAll() // automations is an array from the users database... automationItems is an activity array. I cut this part because its not needed for the question // Sort automations array on date let sortedAutomationItems = automationItems.sorted(by: { (lhs, rhs) -> Bool in return lhs.date < rhs.date }) let nextAutomation = sortedAutomationItems[0] let secondsBetweenNowAndNextAutomation = nextAutomation.date.timeIntervalSince(now) self.log.content(category: "Background Task", message: "Next Automation \(nextAutomation.title) on \(nextAutomation.date)") automationActivity.invalidate() automationActivity.interval = secondsBetweenNowAndNextAutomation automationActivity.repeats = false automationActivity.qualityOfService = QualityOfService.userInitiated automationActivity.schedule {(completion: NSBackgroundActivityScheduler.CompletionHandler) in self.isBackgroundAutomationTaskRunning = true self.log.content(category: "Background Task", message: "Automation \(nextAutomation.title) is running") // do something self.runAutomation(nextAutomation) // schedule next fire date DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { NotificationCenter.default.post(name: .automationComplete, object: nil, userInfo: nil) } completion(NSBackgroundActivityScheduler.Result.finished) } } catch { log.content(category: "Automations", message: "Failed to fetch AutomationDB items: \(error)") } }
NSBackgroundActivityScheduler is basically a wrapper around the XPC activity API <xpc/activity.h>. That header has a bunch of helpful info about the conceptual background to this API. And another great source of info is the WWDC presentations where the API was introduced:
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
WWDC 2013 Session 702 Efficient Design with XPC
WWDC 2013 Session 712 Energy Best Practices
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"