Swift Academy · 课时

时间线提供程序与快照

随时间提供 Widget 内容。

第 2 / 4 课13 个步骤

时间线提供程序与快照 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

提供程序的职责

小组件不会持续自行更新。相反,TimelineProvider会向 WidgetKit 提供一份预渲染 entries 的时间安排,系统则在正确的时间显示每个 entry。提供程序需要回答三个问题:占位内容、快照和时间线。

import WidgetKit
// TimelineProvider supplies:
//   placeholder(in:) -> instant skeleton
//   getSnapshot(in:)  -> one entry for previews
//   getTimeline(in:)  -> future entries + refresh policy

遵循 TimelineProvider

提供程序通过关联的 Entry类型遵循 TimelineProvider。您需要实现三个方法;每个方法都会提供一个 Context,用于描述 family 以及当前是否为预览。

import WidgetKit
struct WeatherProvider: TimelineProvider {
    typealias Entry = WeatherEntry
    func placeholder(in context: Context) -> WeatherEntry {
        WeatherEntry(date: Date(),
            temperature: 20, condition: "Sunny")
    }
    // getSnapshot and getTimeline follow
}

占位内容

placeholder(in:)必须使用具有代表性的虚拟数据立即返回。系统会在真实小组件加载期间以及小组件图库中,将其显示为经过遮罩处理的骨架。这里绝不要执行网络或磁盘操作。

import WidgetKit
func placeholder(in context: Context) -> WeatherEntry {
    // Synchronous, fake data, no I/O
    WeatherEntry(date: Date(),
        temperature: 0, condition: "--")
}

快照

getSnapshot会为小组件图库预览等临时场景提供单个 entry。它应当快速返回。当 context.isPreview为 true 时,请使用示例数据,而不要执行缓慢的获取操作,这样图库才能即时显示。

import WidgetKit
func getSnapshot(
    in context: Context,
    completion: @escaping (WeatherEntry) -> Void) {
    if context.isPreview {
        completion(WeatherEntry(date: Date(),
            temperature: 22, condition: "Clear"))
    } else {
        completion(currentEntry())
    }
}

时间线

getTimeline是核心:您需要构建一个未来 entries 数组,并在 Timeline中将其与刷新策略打包。系统会在每个 entry 的 date 渲染它,然后按照策略请求新的时间线。

import WidgetKit
func getTimeline(
    in context: Context,
    completion: @escaping (Timeline<WeatherEntry>) -> Void) {
    let entries = buildEntries()
    let timeline = Timeline(
        entries: entries, policy: .atEnd)
    completion(timeline)
}

刷新策略

重新加载策略控制 WidgetKit 何时请求下一条时间线:最后一个 entry 的 date 之后使用 .atEnd,在指定时间使用 .after(date),或者直到您手动重新加载前使用 .never。系统会为这些操作分配 budget,因此不要期待每秒更新。

import WidgetKit
// .atEnd            -> reload after final entry
// .after(someDate)  -> reload at a chosen time
// .never            -> only on manual reloadTimelines
let policy = TimelineReloadPolicy.atEnd
_ = policy

构建未来的条目

一种常见模式是预先计算未来几小时的数据,这样小组件无需每次都唤醒您的代码即可更新。从 now 开始向未来按时间间隔生成 entries,每个 entry 都保存对应时刻的数据。

import WidgetKit
import Foundation
func hourlyEntries() -> [WeatherEntry] {
    var entries: [WeatherEntry] = []
    let now = Date()
    for hour in 0..<6 {
        let date = Calendar.current.date(
            byAdding: .hour, value: hour, to: now)!
        entries.append(WeatherEntry(date: date,
            temperature: 18 + hour, condition: "Sunny"))
    }
    return entries
}

时间线中的异步数据

如果必须从网络获取数据,请在调用完成回调之前执行。将异步工作封装在 Task中,并只在数据到达后完成操作。请保持快速,因为提供程序的时间 budget 很紧。

import WidgetKit
func getTimeline(
    in context: Context,
    completion: @escaping (Timeline<WeatherEntry>) -> Void) {
    Task {
        let entry = await fetchForecast()
        let timeline = Timeline(
            entries: [entry], policy: .after(
                Date().addingTimeInterval(3600)))
        completion(timeline)
    }
}
func fetchForecast() async -> WeatherEntry {
    WeatherEntry(date: Date(),
        temperature: 21, condition: "Cloudy")
}

相关性与 budget

WidgetKit 会限制每天的刷新频率,以保护电池电量。您无法强制频繁更新。请为每条时间线提供多个 entries,并选择合理的重新加载时间;只有在数据发生有意义的变化时,才从应用调用 reloadTimelines。

import WidgetKit
// The system, not you, decides exact refresh timing.
// Strategy: pre-bake multiple entries + a sensible policy
// + app-driven reloads on real changes.
let budget = "refreshes are budgeted by the OS"
_ = budget

可配置小组件的提供程序

对于使用 AppIntentConfiguration的小组件,请改用 AppIntentTimelineProvider。它的方法会接收用户配置的意图,因此您可以获取所选选项对应的数据(所选城市、账户等)。

import WidgetKit
// AppIntentTimelineProvider adds the configuration:
//   func timeline(for configuration: MyIntent,
//                 in context: Context)
//       async -> Timeline<Entry>
let configurable = "intent-aware provider"
_ = configurable

整合提供程序

完整的提供程序应包含即时返回的占位内容、快速且能识别预览状态的快照,以及带有适当重新加载策略的预先生成 entries 时间线——这样小组件就能在系统 budget 范围内保持最新。

import WidgetKit
// 1. placeholder -> instant dummy
// 2. getSnapshot -> sample when isPreview, else current
// 3. getTimeline -> [entries] + .atEnd or .after
let summary = "three methods, one current widget"
_ = summary

快速检查

回想一下占位内容方法的限制。

回顾

您学习了时间线提供程序:

  • placeholder返回即时的虚拟数据;getSnapshot返回一个 entry(在 isPreview时使用示例数据);getTimeline返回未来的 entries 以及策略。
  • 重新加载策略包括 .atEnd、.after(date)或 .never;OS 会为实际刷新分配 budget。
  • 预先生成多个 entries;在完成操作前执行异步获取。
  • 可配置小组件使用 AppIntentTimelineProvider。
免费开始

用 AI 导师学习 Swift — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
122
课程
409

常见问题解答

「时间线提供程序与快照」课时是免费的吗?

是的 — 「时间线提供程序与快照」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「时间线提供程序与快照」这节课中我会学到什么?

随时间提供 Widget 内容。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「时间线提供程序与快照」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 构建 WidgetKit Widget
  2. 时间线提供程序与快照
  3. 应用扩展概览
  4. 应用意图与快捷指令
← 返回 Swift Academy