Swift 小部件:带有完成处理程序的 getTimeline

问题描述

我有一个 iOS 小部件,我正在尝试每 5 或 15 分钟更新一次。

我是小部件的新手,不了解如何使用异步调用循环时间线。

struct SimpleEntry: TimelineEntry {
    let date: Date
    let configuration: ConfigurationIntent
    let price: Double
}

func getTimeline(for configuration: ConfigurationIntent,in context: Context,completion: @escaping (Timeline<Entry>) -> ()) {
        
        
        networkManager.fetchData { price in
            
            var entries: [SimpleEntry] = []
            let currentDate = Date()
            
            for hourOffset in 0 ..< 5 {
                
                let entryDate = Calendar.current.date(byAdding: .hour,value: hourOffset,to: currentDate)!
                let entry = SimpleEntry(date: entryDate,configuration: configuration,price: price)
                entries.append(entry)
                
            }
            
            let timeline = Timeline(entries: entries,policy: .atEnd)
            completion(timeline)
        }
       
    }

我有一个完成处理程序,它从异步 api 调用中传递价格。

networkManager.fetchData { price in 
}

解决方法

看起来您的 networkManager.fetchData 一次只提供一个价格值。
在这种情况下,如果一次只提供一个条目,那么以下内容就足够了:

func getTimeline(for configuration: ConfigurationIntent,in context: Context,completion: @escaping (Timeline<Entry>) -> ()) {
  networkManager.fetchData { (price) in
    let currentDate = Date()

    //create the entry for the given price
    let entry = SimpleEntry(date: currentDate,configuration: configuration,price: price)

    /*
     If you can predict price values then you need the loop for multiple entries.
     However in your case,it seems this one entry is sufficient
     */
    let entries = [entry]

    //next reload date; 15mins in this case
    let reloadDate = Calendar.current.date(byAdding: .minute,value: 15,to: currentDate)!

    //your timeline with one entry that will refresh after given date
    let timeline = Timeline(entries: entries,policy: .after(reloadDate))
    completion(timeline)
  }
}

通过将 after(_ date:) 指定为 TimelineReloadPolicy,iOS 将在给定日期之后刷新小部件。

时间线的刷新策略指定了 WidgetKit 向提供者请求新时间线的最早日期。默认刷新策略 .atEnd 告诉 WidgetKit 在您提供的时间线条目数组中的最后一个日期之后请求新的时间线。但是,您可以使用 .afterDate 来指示早于或晚于默认日期的不同日期。如果您知道时间线条目结束之前的某个时间点可能会改变时间线,请指定更早的日期。

参考:Apple Documentation on Timeline


这个解决方案是为了解决核心问题,所以最后我想添加一个免责声明,每 15 分钟重新加载一次可能是过度的。因此调整您的逻辑以智能地指定 TimelineReloadPolicy。如果您可以预测值并以更少的网络调用创建多个条目的时间线,那就太好了!如果没有,那么......好吧......祝你好运:)

重要

如果您的小部件在重新加载时向服务器发出请求,并在时间线条目中使用具有特定日期的 afterDate(),请提前计划。 WidgetKit 会尝试遵守您指定的日期,这可能会在多个设备大约同时重新加载您的小部件时导致服务器负载显着增加。

参考:Keeping a Widget Up To Date

更多阅读: