watchOS - Complication shows previous entry

2019-07-29 12:58发布

问题:

I'm creating a watchOS 3 complication that shows departure times from a public transit service. I've created a data model with an array that contains Train objects with a stationName (String) and departureTime (NSDate).

I've implemented the getCurrentTimelineEntry() method and the entries are showing on the watch. The problem is that the watch shows only the previous entry. For example, I've the following departure times:

 Train(startStation: "Station name", endStation: "Station name", departureTime: stringToDate(dateString: "2016-06-20 14:00")),
 Train(startStation: "Station name", endStation: "Station name", departureTime: stringToDate(dateString: "2016-06-20 14:30")),
 Train(startStation: "Station name", endStation: "Station name", departureTime: stringToDate(dateString: "2016-06-20 14:45")),

If the current time is 14:10, the first entry (with time 14:00) is still showing on the watch. Until the current time is 14:30, then that entry is showing up. If the current time is 14:10, I would want to see the 14:30 departure time on my watch.

Can anybody help me with this or point me in the right direction?

func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) {
    if let train = dataProvider.getTrains().nextTrain() {
        handler(timelineEntryForTrain(train: train))
    } else {
        handler(nil)
    }
}


extension Array where Element : OnRailable {
    func nextTrain() -> Element?{
        let now = NSDate()
        for d in self {
            if now.compare(d.departureTime) == .orderedAscending{
                return d
            }
        }

        return nil
    }
}

回答1:

You need to set the timeline date for each entry to be one minute after the previous departure's date. For example:

  • the 14:30 departure's timeline date should be 14:01,
  • the 14:45 departure's timeline date should be 14:31, and so on.

This will produce the desired effect you want, by making the upcoming departure be the current timeline entry, one minute after the previous departure:

  • When it is 14:00, the current departure at 14:00 will be shown,
  • Anytime between 14:01 and 14:30, the departure leaving at 14:30 will be shown,
  • Anytime between 14:31 and 14:45, the departure leaving at 14:45 will be shown, and so on.

This approach is explained in the WWDC 2015 Creating Complications with ClockKit session. In terms of specifying the timeline dates for events, the presenter mentions how

We should put the templates at the end of the previous event so you have adequate time to get to your next event.

Now, the naive solution which Paul mentioned in the context of a calendar complication would be to use the match start date to be the date of our timeline entry, but that would have the drawback that it has for the calendar as well which is you wouldn't be able to look at your complication to see what game is about to start.

You would only be able to see what game has already started.

So we actually want to do the same thing Paul did with the calendar and move all of these entries farther forward.

We will have each entry start at the time when the previous match ended.

In your case, each entry would start right after the time when the previous train departed.

How to implement your complication:

  • Specify a timeline end date to be one minute after the last train of the day has departed. This will grey out the last train's departure details, once the current time has passed its departure time.

  • Specify that you support forward time travel.

  • Supply future timeline entries for upcoming departures in getTimelineEntriesForComplication(_:afterDate:limit:withHandler:). To determine the timeline date for an entry, use the departure details of the entry's previousTrain() method.

If your realtime departure schedule changes (e.g., due to some delay), you can reload the timeline to change any of the upcoming departure times.