Today 扩展:与容器应用程序同步数据

Today extension: syncing data with container app

上下文

我一直在使用 this example project.

来尝试 Today Extensions

该应用程序非常简单:

我的目标如下:每当容器应用程序或小部件中发生数据更改时,我希望两者都能反映更改:

实施

据我了解,容器应用程序和扩展 运行 在各自的进程中,这意味着两个约束:

我也知道,为了访问共享容器,两个目标都必须选择加入同一组 ID 下的应用程序组权利。

数据访问由嵌入式框架管理,TodoKit。它不是将属性保存在内存中,而是直接进入 NSUserDefaults 以获得适当的值:

public struct ShoppingItemStore: ShoppingStoreType {

    private let defaultItems = [
        ShoppingItem(name: "Coffee"),
        ShoppingItem(name: "Banana"),
    ]

    private let defaults = NSUserDefaults(suiteName: appGroupId)

    public init() {}

    public func items() -> [ShoppingItem] {
        if let loaded = loadItems() {
            return loaded
        } else {
            return defaultItems
        }
    }

    public func toggleItem(item: ShoppingItem) {

        let initial = items()

        let updated = initial.map { original -> ShoppingItem in
            return original == item ?
                ShoppingItem(name: original.name, status: !original.status) : original
        }

        saveItems(updated)
    }

    private func saveItems(items: [ShoppingItem]) {

        let boxedItems = items.map { item -> [String : Bool] in
            return [item.name : item.status]
        }

        defaults?.setValue(boxedItems, forKey: savedDataKey)
        defaults?.synchronize()
    }

    private func loadItems() -> [ShoppingItem]? {

        if let loaded = defaults?.valueForKey(savedDataKey) as? [[String : Bool]] {

            let unboxed = loaded.map { dict -> ShoppingItem in

                return ShoppingItem(name: dict.keys.first!, status: dict.values.first!)
            }

            return unboxed
        }

        return nil
    }
}

问题

这是有效的:

这证明我的应用组设置正确。

但是,当我在主应用程序中更改某些内容,然后下拉通知中心时,它完全不同步。这是我不明白的部分。

我的视图直接从共享容器获取数据。每当发生变化时,我都会立即更新共享容器中的数据。

我错过了什么?我怎样才能正确同步这两个?我的数据访问 class 不是 managint any 状态,但我不明白为什么它的行为不正确。

附加信息

嗯,我在这里学到了两件事:

首先,总是仔细检查你的权利,我的权利不知何故搞砸了,这就是共享容器表现如此笨拙的原因。

第二个: 尽管未调用 viewWillAppear(_:),但当您关闭通知中心时,仍然可以从您的应用程序代理触发更新:

func applicationDidBecomeActive(application: UIApplication) {
    NSNotificationCenter.defaultCenter().postNotificationName(updateDataNotification, object: nil)
}

然后在你的视图控制器中:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    NSNotificationCenter.defaultCenter().addObserverForName(updateDataNotification, object: nil, queue: NSOperationQueue.mainQueue()) { (_) -> Void in
        self.tableView.reloadData()
    }
}

override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

更新您的今日小部件很简单:每次下拉通知中心时,都会调用 viewWillAppear(:_),因此您可以在那里查询新数据。

我会尽快在 GitHub 上更新示例项目。