WatchKit 核心数据同步

WatchKit Core Data Sync Up

我的应用程序结构如下

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

Watch Kit 扩展能够从 iOS 应用写入的核心数据中读取数据。

我遇到的问题是,如果我的 iOS 应用程序在我的手表套件应用程序打开时写入数据,我将无法获得更新,因为对象上下文未与磁盘上的数据同步。

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

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

运行 进入类似问题。尽管在 App Group 中创建了一个共享的 Fetched Results Controller,但观察托管对象上下文的变化和刷新托管对象上下文是不可行的。

托管对象上下文缓存特定级别的对象图以供检索,而无需从磁盘上的实际 SQLite 存储中读取。真正在两者之间实现实时同步的唯一可能方法是在 MOC 更改时通过 iOS 应用程序向扩展发送消息,并且每次都从磁盘 destroying/rebuilding 核心数据堆栈发送消息,这不是一个很好的解决方案完全没有。

我认为 iOS 和 Extension 在初始启动时实时同步的用例不是必需的。希望我们在未来的版本中得到更深思熟虑的解决方案来解决这个问题。

我的工作解决方案是使用 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"];
}