widgetPerformUpdateWithCompletionHandler()
让我们有可能让通知中心知道 Today Extension 的内容是否发生了变化。例如:
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) {
// Refresh the widget's contents in preparation for a snapshot.
// Call the completion handler block after the widget's contents have been
// refreshed. Pass NCUpdateResultNoData to indicate that nothing has changed
// or NCUpdateResultNewData to indicate that there is new data since the
// last invocation of this method.
if(has_new_data()) { // There was an update
completionHandler(.NewData)
}
else { // nothing changed!
completionHandler(.NoData)
}
}
但是我们怎么知道内容是否发生了变化?在每个快照上,小部件都是从头开始实例化的。这是一个带有新 PID 的全新过程。所以你不能在你的实例中存储任何属性。如何将当前小部件内容与先前快照的内容进行比较?
我用了Core Data来存储当前的内容,方便以后对比。这很明显并且有效。但随之而来的另一个问题是:如果没有以前的快照怎么办?假设用户删除了小部件只是为了重新添加它。或者用户重新启动。没有以前的快照可能还有更多我现在想不到的原因。无论哪种方式 - 仍然有内容存储在核心数据中。如果这个旧内容和当前内容之间的比较检测到没有变化并且我返回 .NoData
小部件将最终为空,因为通知中心不会重绘内容。
您可能想知道为什么以正确的状态调用 completionHandler
而不是简单地总是返回 .NewData
对我来说如此重要。那是因为当没有变化时我遇到了一点闪烁,仍然返回 .NewData
。我的小部件中有一些图像,当重新绘制小部件时,整个内容会在一毫秒内变得不可见 - 足够长以引起注意。
有什么我想念的吗?我觉得奇怪的是,Apple 提供了一种方法让我们可以选择以不同的状态进行响应,但却无法检测到我们应该响应哪种状态。
最佳答案
理论上您可以使用它来检查自上次调用以来是否有任何新内容,并传回适当的值。我想理论上它可能是多次调用时 View Controller 的同一个实例,但现在显然不是这样。检查内容是否已更改取决于应用程序和扩展程序的性质。由于您正在使用共享核心数据存储来共享数据,因此您可能会执行以下操作:
- 每当应用更改数据时,将当前日期保存在共享用户默认设置中。
- 只要今天扩展程序读取数据,就将当前日期保存在共享用户默认值中。
- 当
widgetPerformUpdateWithCompletionHandler
被调用时,查找这两个日期。如果数据更改比上次扩展读取该数据的时间更近,则返回NCUpdateResultNewData
。如果不是,则返回NCUpdateResultNoData
。
您还可以将这些日期保存在持久存储的元数据中,而不是共享的用户默认值中。 如果每次都是相同的 View Controller ,您可以将步骤 2 中的值保留在内存中,而不是将其保存到文件中。但这同样不是现在的工作方式,并且不清楚何时或是否会改变。
以其他方式保存数据的应用可能需要使用不同的检查,检查的细节取决于它们的应用和扩展程序的工作方式。
在实践中,对于 iOS 8.2,这真的无关紧要,因为扩展环境似乎并不关心您发回什么值。我尝试返回 NCUpdateResultNewData
并将其与每次返回 NCUpdateResultNoData
进行比较。对今天的扩展 View Controller 或其 View 的生命周期绝对没有影响。
顺便说一句,这并不总是一个不同的过程。我尝试将这一行放在今天扩展的 viewDidLoad
中:
NSLog(@"viewDidLoad pid=%d self=%@", getpid(), self);
然后我运行今天的扩展程序,在通知中心上下滚动几次,关闭通知中心,重新打开,得到以下信息:
2015-03-17 15:19:01.203 DemoToday[3484:903442] viewDidLoad pid=3484 self=<TodayViewController: 0x12d508cc0>
2015-03-17 15:19:14.441 DemoToday[3484:903442] viewDidLoad pid=3484 self=<TodayViewController: 0x12d50ade0>
2015-03-17 15:19:23.784 DemoToday[3484:903442] viewDidLoad pid=3484 self=<TodayViewController: 0x12d619c40>
2015-03-17 15:19:29.015 DemoToday[3484:903442] viewDidLoad pid=3484 self=<TodayViewController: 0x12d50abe0>
虽然每次都是不同的 View Controller 实例,但在每种情况下都是相同的 pid。
关于xcode - OS X Today Widget - 如果内容已更改,如何在 NCWidgetProviding.widgetPerformUpdateWithCompletionHandler 中检测?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28162895/