NSUserDefaultsDidChangeNotification和Today Extensions

我正在开发一个带有Today Extension的iPhone应用程序。 该应用程序有一个模型模块,从/加载到NSUserDefaults。 由于我希望这个信息可以被主应用程序和扩展使用,我使用一个应用程序组:

let storage = NSUserDefaults(suiteName: "group.etc.etc.etc...") 

应用程序和扩展程序都可以访问信息,没有任何问题。

主应用程序偶尔会创build一个本地通知来呈现给用户。 该通知有两个与之相关的操作(UIUserNotificationAction)。 其中一个动作触发主应用程序的背景上运行一些代码。 该代码更改NSUserDefaults信息并触发同步。 我的代码是这样的:

 func application(application: UIApplication, handleActionWithIdentifier id: String?, forLocalNotification not: UILocalNotification, completionHandler: () -> ()) { // Interact with model here // New information gets saved to NSUserDefaults userDefaultsStorage.synchronize() completionHandler() } 

现在,在今天分机。 我自然地观察到对NSUserDefaults上的信息所做的任何更改,以便我可以重新加载小部件上的接口:

 override func viewDidLoad() { super.viewDidLoad() // ... NSNotificationCenter.defaultCenter().addObserverForName(NSUserDefaultsDidChangeNotification, object: nil, queue: NSOperationQueue.mainQueue()) { _ in self.reload() } } 

现在,这是我的问题:

  1. 主应用程序安排一个UILocalNotification。 我打开今天的看法,看看我今天的小工具。

  2. 当通知触发时,屏幕上方会出现横幅。

  3. 我滑下这个横幅来揭示这两个动作,我select了我之前提到的那个(今天的小部件仍然在屏幕上)。

我知道一个事实,即该动作在后台正确运行,并且正在对NSUserDefaults上的信息进行更改。

但是,即使今天的小部件一直处于活动状态并且一直处于屏幕上,也不会触发重新加载操作。 经过进一步调查,我可以确认,NSUserDefaultsDidChangeNotification 没有被解雇(我放置了一个断点,它没有触发,并做了一些其他检查)。

我知道通知操作正在进行更改,因为如果我强制重新加载小部件(通过closures并打开今天的视图),小部件会正确更新。

我在网上看到了各种各样的教程,他们说的第一件事就是听这个通知并更新小部件,以便“小部件与NSUserDefaults同步”。 但事情是AFAICT这个通知是绝对无用的! 怎么来的??


注1:当我更改当前小部件中的NSUserDefaults信息时,通知会正确触发。

注2:debugging一个今天的部件是绝对可怕的,顺便说一句。 在对断点和崩溃做出反应之前,总是需要告诉Xcode“附加到名称进程”。 而且iOS不断地为widget创build一个新的过程,所以我必须不断地告诉Xcode再次连接。

从这里doc :

Cocoa包括两种types的通知中心:NSNotificationCenter类在单个进程中pipe理通知。 NSDistributedNotificationCenter类pipe理单台计算机上多个进程的通知。

显然,包含应用程序和今天的扩展是不同的过程,因为当你debugging今天扩展你想附加包含应用程序进程,但NSNotificationCenter只能在一个进程内工作。

为了在包含应用程序和扩展之间进行通信,您可以使用像NSDistributedNotificationCenter一样工作的Darwin Notify Center CFNotificationCenter ,它只能用于osx。

这个想法是使用他们共享的组文件夹内的文件。 在包含应用程序中,您将要发送的数据写入文件,然后发布CFNotification,这将在今天的扩展中被接收。

在今天的扩展中,使用CFNotificationCenterAddObserver来观察CFNotification,一收到它就调用callback函数,其中一个NSNotification必须由于callback而发布是一个C风格的函数,并且“userInfo”不能在CFNotification中传递,收到这个NSNotification对象,它开始从文件中读取数据,用于更新通知中心的当天扩展视图。

你可以使用这个github代码来实现强制加载今天的扩展视图。 这个对我有用。
这是一个很棒的职位。 http://www.atomicbird.com/blog/sharing-with-app-extensions

另一个select是使用setHasContent函数。 当您计划本地标识符时,将content设置为false以隐藏视图,在handleActionWithIdentifier中将其设置为true以显示视图。 这样,当您留在通知中心时,您暂时不会看到该视图,但是当您看到该视图时,这将是更新后的数据。

 let widgetController = NCWidgetController.widgetController() widgetController.setHasContent(false, forWidgetWithBundleIdentifier: "YourTodayWidgetBundleIdentifier") 

但是我认为整个问题是一个罕见的情况,不需要修复,因为您可以获取更新的数据重新加载通知中心或切换到通知选项卡并切换回到今天的选项卡。