一尘不染

NSUserDefaultsDidChangeNotification和Today扩展

swift

我正在开发带有 Today Extension 的iPhone应用 程序
。该应用程序具有一个Model模块,可从加载/保存到NSUserDefaults。由于我希望主应用程序和扩展程序都可以使用此信息,因此我使用了一个应用程序组:

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

应用程序和扩展程序都可以毫无问题地访问信息。

主应用有时可能会创建本地通知以呈现给用户。该通知有两个与之关联的动作(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()
}

现在,在Today Ext。我自然会观察到对信息所做的任何更改,NSUserDefaults以便可以在小部件上重新加载界面:

override func viewDidLoad() {
    super.viewDidLoad()

    // ...

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

现在,这是我的问题:

  1. 主应用程序安排UILocalNotification。我打开今天视图,并查看我的今天小部件。

  2. 触发通知时,屏幕顶部会显示一条横幅。

  3. 我在该横幅上滑行以显示这两个动作,然后选择了我前面提到的一个动作(今天的小部件仍处于活动状态并显示在屏幕上)。

我知道事实是该操作在后台正确运行,并且正在对上的信息进行更改NSUserDefaults

但是,即使 Today窗口小部件
一直处于活动状态并一直显示在屏幕上,也不会触发任何重装操作。经过进一步调查,我可以证实,NSUserDefaultsDidChangeNotification
没有 被解雇(我把一个断点,并没有触发,并做了一些其他检查以及)。

我知道通知操作正在进行更改,因为如果我强制重新加载小部件(通过关闭和打开Today视图),则小部件会正确更新。

我在线上看过各种教程,他们说的第一件事就是听此通知并更新小部件,以使“小部件与NSUserDefaults
保持同步。但事实是,AFAICT的此通知绝对没有用!怎么会??


注1:当我改变的NSUserDefaults的信息 的今天正确插件的通知火灾。

注意2:调试今天的小部件绝对是可怕的,顺便说一句。始终有必要告诉Xcode“按名称附加处理…”,然后它才能对断点和崩溃作出反应。而且iOS一直在为该小部件创建新流程,因此我不得不不断告诉Xcode再次附加。


阅读 283

收藏
2020-07-07

共1个答案

一尘不染

从这里的文档

Cocoa包括两种类型的通知中心:NSNotificationCenter类在单个流程中管理通知。NSDistributedNotificationCenter类可在一台计算机上跨多个进程管理通知。

显然,包含应用程序和Today扩展是不同的进程,因为当您调试Today扩展时,您想附加包含应用程序的进程,但是NSNotificationCenter仅在单个进程中工作。

为了在包含应用程序和扩展程序之间进行通信,您可以使用 Darwin Notify Center
,其功能CFNotificationCenter类似于NSDistributedNotificationCenter,仅适用于osx。

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

在今天的扩展中,用于CFNotificationCenterAddObserver观察者CFNotification,在接收到它后,将调用回调,其中由于回调是C样式函数而必须发布NSNotification,并且在收到此NSNotification后不能在CFNotification中传递“
userInfo”对象,它将开始从文件中读取数据,该文件用于更新Notification Center中的今日扩展视图。

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

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

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

但是我认为整个问题很少见,不需要解决,因为您可以将更新的数据重新加载到通知中心,也可以切换到“通知”选项卡,再切换回“今天”选项卡。

2020-07-07