3

From the data below, ClockKit generates future CLKComplicationTimelineEntry items once, but for past points in time, 24 calls are made! Why is this?

More details:

I'm noticing a curious behavior in my Apple Watch complication.

It supports Time Travel -- I supply data for 1 day past, 4 days into the future. I'm currently trying to be a good citizen and make fewer calls to regenerate my complication data.

To get an idea how often certain calls are made, I put a simple print inside both getTimelineEntries(for:before:limit:withHandler:) and getTimelineEntries(for:after:limit:withHandler:) that outputs the before/after parameters.

When I launch the App/Complication in Simulator, I get the following output:

generate future timeline entries (after date:2016-07-23 10:33:31 +0000)
generate past timeline entries (before date:2016-07-23 10:33:31 +0000)
generate past timeline entries (before date:2016-07-23 09:33:31 +0000)
generate past timeline entries (before date:2016-07-23 08:33:31 +0000)
generate past timeline entries (before date:2016-07-23 07:33:31 +0000)
generate past timeline entries (before date:2016-07-23 06:33:31 +0000)
generate past timeline entries (before date:2016-07-23 05:33:31 +0000)
generate past timeline entries (before date:2016-07-23 04:33:31 +0000)
generate past timeline entries (before date:2016-07-23 03:33:31 +0000)
generate past timeline entries (before date:2016-07-23 02:33:31 +0000)
generate past timeline entries (before date:2016-07-23 01:33:31 +0000)
generate past timeline entries (before date:2016-07-23 00:33:31 +0000)
generate past timeline entries (before date:2016-07-22 23:33:31 +0000)
generate past timeline entries (before date:2016-07-22 22:33:31 +0000)
generate past timeline entries (before date:2016-07-22 21:33:31 +0000)
generate past timeline entries (before date:2016-07-22 20:33:31 +0000)
generate past timeline entries (before date:2016-07-22 19:33:31 +0000)
generate past timeline entries (before date:2016-07-22 18:33:31 +0000)
generate past timeline entries (before date:2016-07-22 17:33:31 +0000)
generate past timeline entries (before date:2016-07-22 16:33:31 +0000)
generate past timeline entries (before date:2016-07-22 15:33:31 +0000)
generate past timeline entries (before date:2016-07-22 14:33:31 +0000)
generate past timeline entries (before date:2016-07-22 13:33:31 +0000)
generate past timeline entries (before date:2016-07-22 12:33:31 +0000)
generate past timeline entries (before date:2016-07-22 11:33:31 +0000)
oelna
  • 2,210
  • 3
  • 22
  • 40
  • What version of watchOS? Are you reloading your timeline or are you extending it? How many past timeline entries do you return per call? What do you mean by "I'm currently trying to be a good citizen and make fever calls to **regenerate** my complication data." Isn't your datasource using an existing static model, and merely returning requested timeline entries? (Providing some code would have helped to answer some questions, and may still be necessary.) –  Jul 23 '16 at 14:01

2 Answers2

2

There's no stipulation that your datasource method will only be called once. You simply need to be prepared to handle the request.

Why does it handle past entries differently than future entries?

I believe this is an optimization designed to prioritize upcoming timeline entries (over recent past entries).

Back in watchOS 2.0.1, the complication server first filled the timeline with future entries, before proceeding to backfill the timeline with past entries. It's certainly understandable how Apple might then choose to batch past entries to prioritize more recent entries over more distant ones.

While Apple has certainly tweaked its code since then, it likely that the same level of attention and detail continues to apply in the current version of watchOS.

What's if it's an expensive operation for me to complete?

If you have to do more than simply use existing complication data at hand, and your data retrieval is tied to the specific request that the system makes, you should refactor that code to move it outside that method.

In general, you want to have prefetched data already on hand that can simply directly be turned into timeline entries.

This becomes far more significant in watchOS 3, when you are not merely updating a complication, but also updating your app in the background. Even if you still need to support watchOS 2 now, you should design how data is fetched and complications are updated, with a view to how watchOS 3 could accomplish updating your entire app.

Why does it call my datasource method more than once?

Apple uses a variety of techniques to optimize how the complication server (or other parts of the operating system) works. All you can do is trust that the system is tuned to reduce its memory and energy usage, and it does what it does for a good reason.

This has actually been a standard practice for many years, and is commonly seen in UITableViewDataSource, where a method like numberOfSectionsInTableView might be called several times.

As another poster has written, the number of times a method is called can change between different versions of the OS.

What if it's a bug?

It's likely working as intended, but if you think it's a bug, you can create a minimal sample project and submit it with a bug report to Apple.

An unrelated note about time travel

I noticed that you want to offer 4 days of future time travel entries. This will exceed the time travel sliding window.

For efficiency's sake, you may want to consider latestTimeTravelDate:

When constructing your timeline, do not create any entries after this date. Doing so is a waste of time because those entries will not be displayed right away.

Community
  • 1
  • 1
  • 1
    Thanks! Good tip about `latestTimeTravelDate` too – implemented immediately. The behavior seems to have stopped. Can't tell whether it was a bug on my side or watchOS decided to not update as much. I have since tried to optimize the amount of complication date entries and increased the time between updates to about 4 per day. – oelna Jul 31 '16 at 08:32
0

I’m almost certain this is actually the same issue I encountered in my watchOS app; my code was generating an array of timeline entries ordered from most recent to least recent, when the Complication server wants entries in order from least recent to most recent.

The complication server was thus invalidating all but the first entry I generated, and requesting more updates immediately before that entry.

My fix was to change my getTimelineEntries(for:after:limit:withHandler:) function from appending entries to inserting at index 0.

ticky
  • 107
  • 8