更新Apple Watch并发症数据的流程是什么? [英] What is the flow for updating complication data for Apple Watch?

查看:132
本文介绍了更新Apple Watch并发症数据的流程是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在互联网上关注许多教程,以学习如何设置并发症.我可以按预期设置并发症.

直到初始时间轴条目到期. 12小时后,我不知道如何对其进行更新以使并发症持续存在.我会分享我下面的所有内容,希望有人可以帮助我填写内容.

在这里,我为要显示在并发症上的数据创建变量.

struct data = {
var name: String
var startString: String
var startDate: NSDate
}

以下数组是此数据的容器.

var dataArray = [data]

这可以在手表锁定时显示并发症.

func getPrivacyBehaviorForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationPrivacyBehavior) -> Void) {
    handler(.ShowOnLockScreen)
}

这可以使并发症向前移动.

func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) -> Void) {
    handler([.Forward])
}

在这里,我将时间轴的开始时间设置为现在.

func getTimelineStartDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) {
    handler(NSDate())
}

在这里,我将时间轴的结束时间设置为从现在开始等于12小时.

func getTimelineEndDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) {
    handler(NSDate(timeIntervalSinceNow: (60 * 60 * 12)))
}

在这里,我创建并发症的模板.这是为了在用户浏览我的手表上的所有并发症时为他们显示我的并发症的示例数据.

func getPlaceholderTemplateForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTemplate?) -> Void) {

    let headerTextProvider = CLKSimpleTextProvider(text: "Some Data")
    let body1TextProvider = CLKSimpleTextProvider(text: "Some Data Time")
    let template = CLKComplicationTemplateModularLargeStandardBody()
    template.headerTextProvider = headerTextProvider
    template.body1TextProvider = body1TextProvider

    handler(template)
}

这将为并发症创建第一个时间轴条目.一旦启用了并发症,该代码就会运行并立即相应地填充并发症.

func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimelineEntry?) -> Void) {

    createData()

    if complication.family == .ModularLarge {

        if dataArray.count != 0 {

            let firstData = dataArray[0]
            let headerTextProvider = CLKSimpleTextProvider(text: firstData.name)
            let body1TextProvider = CLKSimpleTextProvider(text: firstData.startString)
            let template = CLKComplicationTemplateModularLargeStandardBody()
            template.headerTextProvider = headerTextProvider
            template.body1TextProvider = body1TextProvider
            let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: template)
            handler(timelineEntry)
        } else {
            let headerTextProvider = CLKSimpleTextProvider(text: "No Data")
            let body1TextProvider = CLKSimpleTextProvider(text: "Create some data")
            let template = CLKComplicationTemplateModularLargeStandardBody()
            template.headerTextProvider = headerTextProvider
            template.body1TextProvider = body1TextProvider

            let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: template)
            handler(timelineEntry)
        }

    } else {
        handler(nil)
    }

}

在这里,我为当前拥有的所有数据创建时间线条目.

func getTimelineEntriesForComplication(complication: CLKComplication, afterDate date: NSDate, limit: Int, withHandler handler: ([CLKComplicationTimelineEntry]?) -> Void) {

    createData()

    var entries = [CLKComplicationTimelineEntry]()

    for dataObject in dataArray {

        if entries.count < limit && data.startDate.timeIntervalSinceDate(date) > 0 {

            let headerTextProvider = CLKSimpleTextProvider(text: dataObject.name)
            let body1TextProvider = CLKSimpleTextProvider(text: dataObject.startString)
            let template = CLKComplicationTemplateModularLargeStandardBody()
            template.headerTextProvider = headerTextProvider
            template.body1TextProvider = body1TextProvider
            let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(timeInterval: (-10*60), sinceDate: data.startDate), complicationTemplate: template)
            entries.append(timelineEntry)

        }

    }

    handler(entries)

}

这会告诉手表何时更新并发症数据.

func getNextRequestedUpdateDateWithHandler(handler: (NSDate?) -> Void) {
    handler(NSDate(timeIntervalSinceNow: 60 * 60 * 6))
}

这是我遇到问题的地方.

如何创建新数据并重新加载时间轴?流量是多少?我不是要延长时间表,而是要完全替换它.我完全不知所措.关于这一点, Apple的文档相当模糊.我知道我需要实现以下方法,但是我不知道该怎么做.有人可以帮我填写此代码吗?

func requestedUpdateDidBegin() {
    createData() //I assume createData() goes here? If so, how do I populate the new timeline entries based on the results?
}

func requestedUpdateBudgetExhausted() {
    //This can't possibly be the case as I haven't gotten it to work once.
}

func reloadTimelineForComplication(complication: CLKComplication!) {
      //This method appears to do nothing.
}

更新:

感谢El Tea,我已经开始工作了.我需要将CLKComplicationServer的实例添加到requestUpdateDidBegin并将reloadTimeline方法放入其中.

这是更新的代码:

func requestedUpdateDidBegin() {
    print("Complication update is starting")

    createData()

    let server=CLKComplicationServer.sharedInstance()

    for comp in (server.activeComplications) {
        server.reloadTimelineForComplication(comp)
        print("Timeline has been reloaded!")
    }

}

func requestedUpdateBudgetExhausted() {
    print("Budget exhausted")
}

解决方案

按时间间隔进行的并发症刷新的流程遵循以下顺序:

  • iOS会调用您的函数requestedUpdateDidBegin()requestedUpdateBudgetExhausted()(如果预算用尽,您将无法进行任何更新,直到获得更多执行时间为止).
  • requestedUpdateDidBegin() 内部,您必须调用reloadTimelineForComplication()extendTimelineForComplication()来指定要重新加载或添加数据的并发症.如果您不这样做,那么什么也不会发生!
  • 取决于调用的是reload还是extend,iOS会调用getCurrentTimelineEntryForComplication()getTimelineEntriesForComplication()之一或两者
  • 无论您是否更新并发症,iOS都会调用getNextRequestedUpdateDateWithHandler()来查找您何时希望再次重复上述步骤.

注意:最后两个步骤不一定必须按此顺序进行.

该过程以这种方式工作,因此iOS不会要求您重复重新生成相同的数据.它使您有机会在requestedUpdateDidBegin()中决定是否需要更新并发症.如果不是这样,您的代码应该只返回. (这减少了并发症的执行时间,并有助于避免iOS由于使用了每日预算而使您的应用停止进一步的更新).但是,如果您确实有新数据,则需要通过调用reloadTimelineForComplication()extendTimelineForComplication()

来告知iOS

据我所知,除了没有在requestedUpdateDidBegin()中请求重新加载或扩展之外,您在此处编写的所有内容看起来都不错.您的并发症可能在一个以上的位置在表盘上可见,并且不同的模板具有不同的显示行为,因此您必须使所有这些无效.这是我的代码:

func requestedUpdateDidBegin() {

    //Not shown: decide if you actually need to update your complication.
    //If you do, execute the following code:

    let server=CLKComplicationServer.sharedInstance()

    for comp in (server.activeComplications) {
        server.reloadTimelineForComplication(comp)
    }
}

请注意,除了时间间隔外,还有其他方式来启动刷新,包括推送警报,在Watch应用运行时执行重新加载,或将Watch Connectivity框架与WCSession结合使用,以使您的手机应用发送更新数据,以便通过来立即显示更新数据transferCurrentComplicationUserInfo().要获取更多信息,请查看Apple文档中的更新并发症数据. >

我已经成功地在模拟器上测试了短至十分钟的更新间隔.由于执行时间的预算,您可能不应该在真正的手表上经常更新该代码,但这将使您无需等待12个小时即可测试您的代码.

I've been following a lot of tutorials on the internet to learn how to set up the complication. I have no problem getting the complication set up as expected.

Until the initial timeline entries expire. After 12 hours, I do not know how to update it to keep the complication live. I'll share everything I have below and hopefully somebody can help fill me in.

Here, I create the variables for my data that I want to display on the complication.

struct data = {
var name: String
var startString: String
var startDate: NSDate
}

The following array is a container for this data.

var dataArray = [data]

This allows the complication to be shown when the watch is locked.

func getPrivacyBehaviorForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationPrivacyBehavior) -> Void) {
    handler(.ShowOnLockScreen)
}

This allows forward Time Travel on the complication.

func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) -> Void) {
    handler([.Forward])
}

Here, I set the starting time of the timeline to be equal to now.

func getTimelineStartDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) {
    handler(NSDate())
}

Here, I set the ending time of the timeline to be equal to 12 hours from now.

func getTimelineEndDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) {
    handler(NSDate(timeIntervalSinceNow: (60 * 60 * 12)))
}

Here, I create the template of the complication. This is to show sample data for users when they see my complication while browsing all complications on their watch.

func getPlaceholderTemplateForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTemplate?) -> Void) {

    let headerTextProvider = CLKSimpleTextProvider(text: "Some Data")
    let body1TextProvider = CLKSimpleTextProvider(text: "Some Data Time")
    let template = CLKComplicationTemplateModularLargeStandardBody()
    template.headerTextProvider = headerTextProvider
    template.body1TextProvider = body1TextProvider

    handler(template)
}

This creates the very first timeline entry for the complication. As soon as the complication is enabled, this code will be run and immediately populate the complication accordingly.

func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimelineEntry?) -> Void) {

    createData()

    if complication.family == .ModularLarge {

        if dataArray.count != 0 {

            let firstData = dataArray[0]
            let headerTextProvider = CLKSimpleTextProvider(text: firstData.name)
            let body1TextProvider = CLKSimpleTextProvider(text: firstData.startString)
            let template = CLKComplicationTemplateModularLargeStandardBody()
            template.headerTextProvider = headerTextProvider
            template.body1TextProvider = body1TextProvider
            let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: template)
            handler(timelineEntry)
        } else {
            let headerTextProvider = CLKSimpleTextProvider(text: "No Data")
            let body1TextProvider = CLKSimpleTextProvider(text: "Create some data")
            let template = CLKComplicationTemplateModularLargeStandardBody()
            template.headerTextProvider = headerTextProvider
            template.body1TextProvider = body1TextProvider

            let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: template)
            handler(timelineEntry)
        }

    } else {
        handler(nil)
    }

}

This is where I create timeline entries for all of the data that I currently have.

func getTimelineEntriesForComplication(complication: CLKComplication, afterDate date: NSDate, limit: Int, withHandler handler: ([CLKComplicationTimelineEntry]?) -> Void) {

    createData()

    var entries = [CLKComplicationTimelineEntry]()

    for dataObject in dataArray {

        if entries.count < limit && data.startDate.timeIntervalSinceDate(date) > 0 {

            let headerTextProvider = CLKSimpleTextProvider(text: dataObject.name)
            let body1TextProvider = CLKSimpleTextProvider(text: dataObject.startString)
            let template = CLKComplicationTemplateModularLargeStandardBody()
            template.headerTextProvider = headerTextProvider
            template.body1TextProvider = body1TextProvider
            let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(timeInterval: (-10*60), sinceDate: data.startDate), complicationTemplate: template)
            entries.append(timelineEntry)

        }

    }

    handler(entries)

}

This tells the watch when to update the complication data.

func getNextRequestedUpdateDateWithHandler(handler: (NSDate?) -> Void) {
    handler(NSDate(timeIntervalSinceNow: 60 * 60 * 6))
}

This is where I'm running into problems.

How do I create my new data and reload the timeline? What is the flow? I'm not trying to extend the timeline, but rather to completely replace it. I'm at a complete loss. Apple's docs are pretty vague when it comes to this point. I know that I need to implement the following methods, but I don't know how. Can somebody help me to fill in this code?

func requestedUpdateDidBegin() {
    createData() //I assume createData() goes here? If so, how do I populate the new timeline entries based on the results?
}

func requestedUpdateBudgetExhausted() {
    //This can't possibly be the case as I haven't gotten it to work once.
}

func reloadTimelineForComplication(complication: CLKComplication!) {
      //This method appears to do nothing.
}

Update:

Thanks to El Tea, I've got it working. I need to add an instance of CLKComplicationServer to requestedUpdateDidBegin and put the reloadTimeline method inside.

Here is the updated code:

func requestedUpdateDidBegin() {
    print("Complication update is starting")

    createData()

    let server=CLKComplicationServer.sharedInstance()

    for comp in (server.activeComplications) {
        server.reloadTimelineForComplication(comp)
        print("Timeline has been reloaded!")
    }

}

func requestedUpdateBudgetExhausted() {
    print("Budget exhausted")
}

解决方案

The flow for a complication refresh that is being done on a time interval follows this sequence:

  • iOS calls your function requestedUpdateDidBegin() or requestedUpdateBudgetExhausted() (If your budget is exhausted nothing you do will cause an update until you're given more execution time.)
  • Inside of requestedUpdateDidBegin() you have to call reloadTimelineForComplication() or extendTimelineForComplication() to specify which of your complications you want reloaded or to have data added to. If you don't do this, nothing happens!
  • Depending on if you called reload or extend, iOS makes calls to one or both of getCurrentTimelineEntryForComplication() and getTimelineEntriesForComplication()
  • Irrespective of whether or not you updated your complication, iOS calls getNextRequestedUpdateDateWithHandler() to find out when you next want the above steps to repeat.

Note: the last two steps don't necessarily have to happen in that order.

The process works this way so that iOS doesn't ask you to repeatedly regenerate the same data. It gives you a chance in requestedUpdateDidBegin() to decide if your complication needs updating. If it doesn't, your code should just return. (This reduces your complication's execution time and helps avoid iOS from cutting off your app from further updates for having used its daily budget). But if you do have new data, you need to tell iOS by calling reloadTimelineForComplication() or extendTimelineForComplication()

From what I can tell, everything you've written there looks good other than you weren't requesting a reload or extend inside requestedUpdateDidBegin(). It's possible for your complication to be visible on the watch face in more than one position, and for different templates to have different display behaviours, so you have to invalidate all of them. Here is what my code looks like:

func requestedUpdateDidBegin() {

    //Not shown: decide if you actually need to update your complication.
    //If you do, execute the following code:

    let server=CLKComplicationServer.sharedInstance()

    for comp in (server.activeComplications) {
        server.reloadTimelineForComplication(comp)
    }
}

Note that besides time intervals that there are other ways to initiate refreshes including push alerts, executing reloads when your watch app runs, or using the Watch Connectivity framework with a WCSession to have your phone app send update data to be displayed immediately via transferCurrentComplicationUserInfo(). See Updating Your Complication Data in Apple's docs for more info.

I've had success in the simulator testing update intervals as short as ten minutes. You probably shouldn't update that frequently on the real watch due to the execution time budget, but this will allow you to test your code without waiting 12 hours.

这篇关于更新Apple Watch并发症数据的流程是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆