今日扩展:与容器应用同步数据

Posted

技术标签:

【中文标题】今日扩展:与容器应用同步数据【英文标题】:Today extension: syncing data with container app 【发布时间】:2015-06-13 20:00:52 【问题描述】:

上下文

我一直在使用 this example project 玩 Today Extensions。

应用程序非常简单:

在包含的应用程序中,您有一个待办事项列表,您可以将其标记为已完成 在“今日”小部件中,您会看到相同的列表,但您可以使用分段控件在已完成和未完成的项目之间切换。

我的目标如下:无论何时发生数据更改,无论是在容器应用程序中还是在小部件中,我都希望两者都反映这些更改:

如果我在容器应用中将某个项目标记为已完成,然后下拉通知中心,小部件应该会更新 当我在小部件中执行相同操作,然后返回应用程序时,应用程序的状态应该会更新

实现

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

NSUserDefaultsDidChangeNotification 没用。 管理内存中的模型实例是没有用的。

我还知道,为了访问共享容器,两个目标都必须选择加入同一组 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
    

问题

以下是有效的:

当我在主应用程序中修改列表,然后停止模拟器,然后从 Xcode 启动 Today 目标时,它反映了正确的状态。反之亦然。

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

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

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

我错过了什么?如何正确同步这两个?我的数据访问类不是管理 any 状态,但我不明白为什么它的行为不正确。

附加信息

我知道MMWormhole。不幸的是,这对我来说不是一个选择,因为我需要在不包含任何第三方解决方案的情况下实现适当的功能。

这个terrific article 涵盖了这个主题,我可能需要使用NSFilePresenter,虽然它看起来很麻烦,而且我还没有完全理解这个机制。我真的希望,有一个比这个更简单的解决方案。

【问题讨论】:

【参考方案1】:

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

首先,始终仔细检查您的权利,我的权利不知何故搞砸了,这就是共享容器表现得如此尴尬的原因。

第二: 虽然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)

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

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

【讨论】:

以上是关于今日扩展:与容器应用同步数据的主要内容,如果未能解决你的问题,请参考以下文章

大数据必学Java基础(六十一):同步类容器对比应用

iOS8 扩展:将 CoreData 与包含的应用程序同步

WatchKit 核心数据同步

ios 应用容器与 icloud 同步

Docker Review - 使用docker volume数据卷实现容器内的数据与宿主机同步

Docker 容器与主机不同步