WatchKit 核心数据同步

Posted

技术标签:

【中文标题】WatchKit 核心数据同步【英文标题】:WatchKit Core Data Sync Up 【发布时间】:2015-01-06 03:20:39 【问题描述】:

我有一个应用结构如下

ios 应用程序将数据写入核心数据,核心数据具有存储在共享应用程序组中的持久存储。

Watch Kit 扩展能够从 Core Data 中读取由 iOS 应用编写的数据。

我遇到的问题是,如果我的 iOS 应用程序在我的手表工具包应用程序打开时写入数据,我没有得到更新,因为对象上下文没有与磁盘上的数据同步。

有没有一种方法,因为我的手表套件扩展只读取数据才能刷新上下文并强制它从磁盘上的数据再次加载?

【问题讨论】:

【参考方案1】:

我的工作解决方案是使用MMWormhole 将通知 (NSManagedObjectContextDidSaveNotification) 从 iPhone 应用程序发送到我的手表应用程序。在手表应用程序的控制器中,我使用了 NSManagedObjectContext 的mergeChangesFromContextDidSaveNotification: 方法。

// in iPhone app's notification handler
MMWormhole *wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@"your.group.container.identifier" optionalDirectory:nil];
[wormhole passMessageObject:notification identifier:@"your notification identifier"];

// in WKInterfaceController's awakeWithContext: method
MMWormhole *wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@"your.group.container.identifier" optionalDirectory:nil];
[wormhole listenForMessageWithIdentifier:@"your notification identifier" listener:^(id messageObject) 
    [self.managedObjectContext mergeChangesFromContextDidSaveNotification:messageObject];
];

然后 NSFetchedResultsController 完成了 UI 更新的所有其他工作。

您必须为您的 NSManagedObject 子类实现 NSCoding 协议中的 initWithCoder:encodeWithCoder: 方法,因为 MMWormhole 使用 NSKeyedArchiver 作为序列化媒介。

- (id)initWithCoder:(NSCoder *)decoder 
    NSManagedObjectContext *context = ... // use your NSManagedObjectContext 
    NSPersistentStoreCoordinator *coordinator = ...; //use your NSPersistentStoreCoordinator
    NSURL *url = (NSURL *)[decoder decodeObjectForKey:@"URIRepresentation"];
    NSManagedObjectID *managedObjectID = [coordinator managedObjectIDForURIRepresentation:url];
    self = [context existingObjectWithID:managedObjectID error:nil];
    return self;


- (void)encodeWithCoder:(NSCoder *)encoder 
    [encoder encodeObject:[[self objectID] URIRepresentation] forKey:@"URIRepresentation"];

【讨论】:

我已经有一段时间没有看这个项目了,但是一旦我再次开始工作,这就是我想尝试的。可能没有 MMWormhole。 很想看看这是如何在 Swift 中完成的。覆盖 initWithCoder 似乎没有按预期工作。【参考方案2】:

我遇到了同样的问题。我在 NSManagedObjectContext 中使用了- (void)refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag 来获取托管对象的最新数据。

【讨论】:

好吧,我的问题有点困难,我使用的是 NSFetchedResultsController,当我的 iOS 应用程序写入 Core Data 时,watchkit 中没有触发回调。我想我不必在 watchkit 中使用 NSFetchedResultsController 我可能只需要定期执行提取。因为我不是试图更新单个对象,而是强制上下文检测磁盘上的变化。 我怀疑你会在你的手表套件扩展中收到回调(尽管我可能是错的)。我认为回调来自对象上下文发布通知,而不是来自它观察数据存储的变化。如果您在查询具有陈旧数据时遇到问题,请尝试将 NSManagedObjectContext 上的 stalenessInterval 更改为 0。 是的,我不会在我的扩展程序中从 iOS 应用程序中获取上下文通知。我在想我要做的是让扩展程序和应用程序在彼此之间发送消息,或者只是定期重置核心数据。我会看看陈旧值,这也可能有帮助。 应用程序和扩展程序作为两个不同的进程运行。 Core Data 没有提供让两个不同进程感知对象、上下文或存储更改的方法。 给每个上下文 -reset 消息。【参考方案3】:

遇到了类似的问题。尽管在 App Group 中创建了一个共享的 Fetched Results Controller 来观察托管对象上下文的变化并刷新托管对象上下文是不可行的。

托管对象上下文缓存了一定级别的对象图以供检索,而无需从磁盘上的实际 SQLite 存储中读取。真正实现两者之间实时同步的唯一潜在方法是在 MOC 更改时通过 iOS 应用程序向 Extension 发送消息,并且每次都从磁盘销毁/重建 Core Data 堆栈,这根本不是一个好的解决方案。

我相信 iOS 和 Extension 在初始启动时实时同步的用例并不是必需的。希望我们在未来的版本中能更深入地解决这个问题。

【讨论】:

以上是关于WatchKit 核心数据同步的主要内容,如果未能解决你的问题,请参考以下文章

如何强制 iCloud 与核心数据进行同步?

使用 iCloud 进行核心数据同步

核心数据同步问题

如何控制 iCloud 何时同步我的核心数据?

核心数据 + iCloud 同步 NSPersistentStoreDidImportUbiquitousContentChangesNotification

同步核心数据时,是不是需要调用 URLForUbiquityContainerIdentifier: ?