我正在开发带有 Today Extension 的iPhone应用 程序 。该应用程序具有一个Model模块,可从加载/保存到NSUserDefaults。由于我希望主应用程序和扩展程序都可以使用此信息,因此我使用了一个应用程序组:
NSUserDefaults
let storage = NSUserDefaults(suiteName: "group.etc.etc.etc...")
应用程序和扩展程序都可以毫无问题地访问信息。
主应用有时可能会创建本地通知以呈现给用户。该通知有两个与之关联的动作(UIUserNotificationAction)。这些操作之一触发一些代码在主应用程序的后台运行。该代码将更改NSUserDefaults信息并触发同步。我的代码是这样的:
UIUserNotificationAction
func application(application: UIApplication, handleActionWithIdentifier id: String?, forLocalNotification not: UILocalNotification, completionHandler: () -> ()) { // Interact with model here // New information gets saved to NSUserDefaults userDefaultsStorage.synchronize() completionHandler() }
现在,在Today Ext。我自然会观察到对信息所做的任何更改,NSUserDefaults以便可以在小部件上重新加载界面:
override func viewDidLoad() { super.viewDidLoad() // ... NSNotificationCenter.defaultCenter().addObserverForName(NSUserDefaultsDidChangeNotification, object: nil, queue: NSOperationQueue.mainQueue()) { _ in self.reload() } }
现在,这是我的问题:
主应用程序安排UILocalNotification。我打开今天视图,并查看我的今天小部件。
触发通知时,屏幕顶部会显示一条横幅。
我在该横幅上滑行以显示这两个动作,然后选择了我前面提到的一个动作(今天的小部件仍处于活动状态并显示在屏幕上)。
我知道事实是该操作在后台正确运行,并且正在对上的信息进行更改NSUserDefaults。
但是,即使 Today窗口小部件 一直处于活动状态并一直显示在屏幕上,也不会触发任何重装操作。经过进一步调查,我可以证实,NSUserDefaultsDidChangeNotification在 没有 被解雇(我把一个断点,并没有触发,并做了一些其他检查以及)。
NSUserDefaultsDidChangeNotification
我知道通知操作正在进行更改,因为如果我强制重新加载小部件(通过关闭和打开Today视图),则小部件会正确更新。
我在线上看过各种教程,他们说的第一件事就是听此通知并更新小部件,以使“小部件与NSUserDefaults” 保持同步。但事实是,AFAICT的此通知绝对没有用!怎么会??
注1:当我改变的NSUserDefaults的信息 内 的今天正确插件的通知火灾。
注意2:调试今天的小部件绝对是可怕的,顺便说一句。始终有必要告诉Xcode“按名称附加处理…”,然后它才能对断点和崩溃作出反应。而且iOS一直在为该小部件创建新流程,因此我不得不不断告诉Xcode再次附加。
从这里的文档:
Cocoa包括两种类型的通知中心:NSNotificationCenter类在单个流程中管理通知。NSDistributedNotificationCenter类可在一台计算机上跨多个进程管理通知。
显然,包含应用程序和Today扩展是不同的进程,因为当您调试Today扩展时,您想附加包含应用程序的进程,但是NSNotificationCenter仅在单个进程中工作。
为了在包含应用程序和扩展程序之间进行通信,您可以使用 Darwin Notify Center ,其功能CFNotificationCenter类似于NSDistributedNotificationCenter,仅适用于osx。
CFNotificationCenter
NSDistributedNotificationCenter
想法是使用他们共享的组文件夹中的文件。在包含应用程序中,您可以将要发送的数据写入文件中,然后发布CFNotification,今天扩展名将接收到。
在今天的扩展中,用于CFNotificationCenterAddObserver观察者CFNotification,在接收到它后,将调用回调,其中由于回调是C样式函数而必须发布NSNotification,并且在收到此NSNotification后不能在CFNotification中传递“ userInfo”对象,它将开始从文件中读取数据,该文件用于更新Notification Center中的今日扩展视图。
CFNotificationCenterAddObserver
您可以使用此github代码实现强制加载今天的扩展视图。这个对我有用。 这是一篇很棒的文章。http://www.atomicbird.com/blog/sharing-with-app- extensions
另一种选择是使用setHasContent函数。计划本地标识符时,将content设置为false以隐藏视图,handleActionWithIdentifier将其设置为true以显示视图。这样,当您留在通知中心时,暂时不会看到该视图,但是当它看到时,它将是更新的数据。
handleActionWithIdentifier
let widgetController = NCWidgetController.widgetController() widgetController.setHasContent(false, forWidgetWithBundleIdentifier: "YourTodayWidgetBundleIdentifier")
但是我认为整个问题很少见,不需要解决,因为您可以将更新的数据重新加载到通知中心,也可以切换到“通知”选项卡,再切换回“今天”选项卡。