0

I'm writing a simple alarm clock application in Swift 3.

The way I'm writing this application is, I have a timer set for 60 seconds, that every time it fires, it checks if an alarm is set for that time, and then fires the alarm.

The purpose of this application is to turn on my HomeKit connected lights when it fires. This is why I can't take the approach of setting a local notifications, because when that executes there's no way to run the code of turning on the lights.

I have this application set to run in the background (as much as apple will allow it), in the way that if the application is open when you lock the phone, it will continue running.
This works perfectly in the simulator, even for long amounts of time. This also works on my phone, when I don't set the alarm for too far ahead. However, when I leave the application on my phone overnight, it rarely works.

To debug this, I created a text file in the application, and set the timer so that when it checks the time, it also writes the time to that text file.

I did this so I could see if the timer would continue to run overnight, for the full night.

Here were my results.

Last night, I went to bed at 4 am, and set an alarm for 8am. (I know that's great, haha) In the text file, when I left the application running, The timer continued to run for a good half hour, with every minute, logging the correct time.

To make it easier to read, I uploaded a screenshot.

https://i.stack.imgur.com/9bV5S.jpg

Notice how it was logging every minute.

However, later on in the night, the timer stopped firing every minute, and started becoming more sporatic.

http://imgur.com/a/8Emd9

Notice how the timer fired at 5:13 am, then 5:25 am, 5:53, and so on.

This has happened for the past couple nights, and I don't know what to do.

I'm not receiving any texts, or anything else that I would think would cause the timer thats supposed to firing every minute, fire every half hour randomly.

Is there anything I can do to make sure that this timer fires every minute reliably?

If you made it this far, thanks so much! This is my first application and It's a struggle working around Apple's background restrictions.
Thanks!

Bista
  • 7,869
  • 3
  • 27
  • 55
Jolaroux
  • 361
  • 1
  • 5
  • 15
  • 1
    Unfortunately iOS is not a good platform for long-running, time-scheduled, background tasks. You can use a server, somewhere, to send a silent push notification to your app at the required time and this will trigger your app to run in the background where you can turn off the lights. Also, limits on background execution are suspended when you are running under the Xcode debugger, so that is why you are seeing differences between the simulator and your device. – Paulw11 Dec 07 '16 at 04:21
  • So when I send the silent push notification, I could run the code to turn on the lights? I thought that that was limited to downloading content from a server. If that's not true that would be great! – Jolaroux Dec 07 '16 at 04:44
  • 1
    You can run whatever code you want in the `didReceiveRemoteNotification` method; you just need to respect the background execution time limits – Paulw11 Dec 07 '16 at 04:45
  • That's great news! Thanks! – Jolaroux Dec 07 '16 at 04:50
  • I got the silent notification working! Just one question, should I call all the code of setting up the home kit devices, and turning them on, in the `appDelegate` file? Or is there a way to call that code that's in another view controller from the appDelegate file. also, is it possible to run the `didRecieveRemoteNotification` function without downloading any data? Xcode is giving me warnings saying that the `completionHandler` isn't doing that. Thanks! – Jolaroux Dec 07 '16 at 17:03
  • 1
    I would normally have non-view comtroller things (such as HomeKit) in its own class. You need to make sure you call the completionHandler that is passed to the `didReceiveRemoteNotification` function, passing a value to indicate the status. In your. See you can just always pass .newData – Paulw11 Dec 07 '16 at 19:26

1 Answers1

0

Your approach is a nonstarter. Apple won't allow you to make an application run constantly in the background. That will drain the users battery in a hurry. You probably want to set up a local notification. You can set those up to go off at any time in the future.

In recent versions of iOS Apple adjusts the time when timers fire in order to conserve battery. I don't know specifically about wildly changing the interval of the timer from the background but that certainly sounds like what's going on.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • I should edit my main post, but this application actually turns on my HomeKit connected lights when the alarm fires. Therefore I can't set up a local Notification because there's no way to execute the code necessary to turn on the lights. That's why I took this approach, I can't think of another way to have this application function. – Jolaroux Dec 07 '16 at 03:41
  • Can you think of any other approach I can take to this? – Jolaroux Dec 07 '16 at 04:00