WatchKit核心数据同步

4
我有一个应用程序的结构如下:
iOS应用程序将数据写入Core Data,该数据具有存储在共享应用程序组中的持久存储。
Watch Kit扩展能够从由iOS应用程序编写的Core Data读取数据。
我的问题是,如果我的iOS应用程序在我的手表应用程序打开时写入数据,我将无法获得更新,因为对象上下文未与磁盘上的数据同步。
是否有一种方法可以刷新上下文并强制从磁盘重新加载数据,因为我的手表扩展仅读取数据?
3个回答

2

我的解决方案是使用MMWormhole从iPhone应用程序向手表应用程序发送通知(NSManagedObjectContextDidSaveNotification)。在手表应用程序的控制器中,我使用了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。 - Douglas Cobb
很想看看这个在Swift中是如何实现的。重写initWithCoder似乎没有按预期工作。 - Daniel

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

我的问题稍微有点复杂,我正在使用NSFetchedResultsController,但当我的iOS应用程序写入Core Data时,watchkit中的回调未被触发。我认为我可能不得不在watchkit中不使用NSFetchedResultsController,而是定期执行获取操作。因为我不是试图更新单个对象,而是强制上下文检测磁盘上的更改。 - Douglas Cobb
我怀疑你的手表扩展程序不会得到回调(虽然我可能错了)。我认为回调来自对象上下文发布通知,而不是从它观察数据存储的变化。如果您在查询中遇到过期数据的问题,请尝试将NSManagedObjectContext上的stalenessInterval更改为0。 - Stephen Johnson
是的,我在我的扩展中无法从iOS应用程序获取上下文通知。 我正在考虑我要做的是让扩展和应用程序彼此发送消息,或者定期重置核心数据。 我会查看过时值,这可能也有所帮助。 - Douglas Cobb
1
应用程序和扩展程序运行为两个不同的进程。Core Data 不提供让两个不同进程意识到对象、上下文或存储变化的方法。 - quellish
@quellish 有一种使用达尔文通知在扩展和应用程序之间发送通知的方法。使用这些通知,您可以在发生通知时重置核心数据。我只是不知道如何重置核心数据。 - erdekhayser
1
给每个上下文发送“reset”消息。 - quellish

1
遇到了类似的问题。尽管在应用程序组中创建了共享的“获取结果控制器”,观察托管对象上下文的更改并刷新托管对象上下文是不可行的。
托管对象上下文会缓存一定级别的对象图,以便从实际的SQLite磁盘存储中检索而无需读取。实际上获得两者之间的实时同步的唯一潜在方法是在MOC更改时通过iOS应用程序向Extension发送消息,并每次从磁盘销毁/重建Core Data堆栈,这并不是一个很好的解决方案。
我认为,在初始启动时iOS和Extension之间的实时同步用例并不是必需的。希望我们能在未来的版本中得到更明确的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接