首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >今天的扩展:用容器应用程序同步数据

今天的扩展:用容器应用程序同步数据
EN

Stack Overflow用户
提问于 2015-06-13 20:00:52
回答 1查看 1.6K关注 0票数 1

上下文

我一直在使用这个例子项目来玩今天的扩展。

这个应用程序非常简单:

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

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

  • 如果我在容器应用程序中将一个项目标记为已完成,然后拉下Notification,则应该更新该小部件
  • 当我在小部件中做同样的操作,然后返回到应用程序时,应用程序的状态应该被更新

实施

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

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

我还知道,为了访问共享容器,两个目标都必须选择进入同一组Id下的App。

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

代码语言:javascript
复制
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启动“今日”目标,它反映了正确的状态。这是事实,反之亦然。

这就验证了,我的应用程序组的设置是否正确。

然而,当我在主应用程序中改变一些东西,然后拉下Notification,它是完全不同步的。这就是我不明白的部分。

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

我遗漏了什么?我如何正确地同步这两者?我的数据访问类没有对任何状态进行管理,但我不明白为什么它的行为不正确。

更多信息

  • 我知道MMWormhole的事。不幸的是,这不是我的选择,因为我需要达到适当的功能,而不包括任何第三方解决方案。
  • 这个绝妙的文章涵盖了这个主题,也许我需要使用NSFilePresenter,尽管它看起来很麻烦,而且我还没有完全理解这个机制。我真的希望有一个比这个更简单的解决方案。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-06-13 21:20:09

我在这里学到了两件事:

首先,总是重复检查您的权限,我的不知怎么搞砸了,这就是共享容器行为如此笨拙的原因。

第二:虽然没有调用viewWillAppear(_:),但当您关闭通知中心时,仍然可以从应用程序委托触发更新:

代码语言:javascript
复制
func applicationDidBecomeActive(application: UIApplication) {
    NSNotificationCenter.defaultCenter().postNotificationName(updateDataNotification, object: nil)
}

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

代码语言:javascript
复制
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上的示例项目。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30822988

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档