1

I am developing a watchOS Complication with type graphicRectangular. Something like the apple activity or heart rate complication. These updates often and display some graph data.

My graph works – showing calendar events in timeline.

I cannot update it "every minute". That would be nice to set a marker for the actual time (check screenshot) in the timeline graph. But that idea is mostly gone since I can only force to update the timeline 50 times a day (as I have read). Apple just says

If your complication has already exceeded its allotted daily budget for execution time, calls to this method do nothing.

So there is nothing I can do, right? Not even when my goal is not submitting it to the AppStore and getting it reviewed?

enter image description here

Now I have developed a function that checks if the text needs to get updated (in screenshot above 13:00 Lorem Ipsum) or the graph has changed and if so triggering the reloadTimeline() method. So not just reloading it every time but only when necessary. But how should I call this function? I've tried in background Task but that only check "when it wants" – I also build a repeatable 30 sec Timer in ExtensionDelegate. That also works – but seems only to work when XCode runs the app – If I stop in XCode then the graph nearly gets only updated every 15 minutes or something (background Task maybe).

Also I have included EventKit observer for storeChanged(). So I can reload the graph if something changed in calendar. That also work well and quote fast when running the app with XCode active. Stopping the app and using it on the watch "outside XCode" seems to have a heavy delay – sometimes it do never work.

When opening the app (tap on complication) the storeChanged() event gets triggered immediately (I think it is this function – I can't really debug that since connected to XCode every works well super fast) and after closing the app the complication is refreshed.


Is there a reason why the storeChanged() event get triggered super fast then running via XCode but is extremely laggy / slow / only triggering when opening the app when not running via XCode?

Is there a reason why my Timer do not run when not running through XCode? When running with XCode I can see debug prints in console from these timed 30 sec "checks". But these seems nothing to do when running outside XCode. Just rarely updating the complication.


Another example: This morning when I put on my watch the graph from yesterday was still visible. So background Task or Timer did not work over night. When opening the app (tap complication) then the graph get refreshed immediately.


Where is the correct place for the EventKit observer or the Timer? ExtensionDelegate or ComplicationController?

Kevin Lieser
  • 951
  • 1
  • 9
  • 25

2 Answers2

2

The reason everything runs fast in Xcode is that when the App is attached to the Debugger the system won't stop executing the background queues. So having an App attached to the debugger will keep all your background queues alive.

The timer runs on the main queue. The main queue is running all the time when the app is attached to the Xcode debugger. When running your app without the debugger the main queue gets suspended when the app enters the background.

To refresh your complication as often as possible you can:

Sadly you can't do more than this. When your complication exceeds Apples limits it won't be refreshed anymore. So it might be better to refresh it every 30 min or something.

  • Thanks! But which is the ComplicationControllerDelegate? Just have a ExtensionDelegate or ComplicationController. The refresh of 50 times a day will be enough – that is not the main problem. The main problem is to get the backgroundTask / Timer running that the check if the complication needs to get updated. Any idea why the Timer is not working properly without XCode? – Kevin Lieser Mar 13 '20 at 11:16
  • I updated the post, let me know if you have any further questions –  Mar 16 '20 at 09:45
  • I also found a solution in preplanning complication states for the future. See my answer. – Kevin Lieser Mar 16 '20 at 13:02
0

I used getTimelineEndDate() and getTimelineEntries(for: after date:) to produce all the other planned complications "views" at initial/refresh time. So I do not need to refresh the complication just to change the "planned content".

I just need to refresh it to fetch changes from EventKit.

Kevin Lieser
  • 951
  • 1
  • 9
  • 25