用新的核心数据初始化 RestKit 的 RKPaginator

Posted

技术标签:

【中文标题】用新的核心数据初始化 RestKit 的 RKPaginator【英文标题】:Initializing RestKit's RKPaginator with fresh core-data 【发布时间】:2013-12-20 12:21:30 【问题描述】:

我有一个RKPaginator,它从服务器加载数据并将其保存到Core Data。加载和分页时,这一切都像魅力一样。但是,Core Data 中的项目是持久的,所以每当我重新进入 viewcontroller 或重新启动应用程序时,所有以前的分页数据仍然在 Core Data 中。

我想在启动应用程序时从一张白纸开始。如何告诉 Core Data 刷新其内容?我尝试了以下代码,但它似乎只能在某些时候工作,而且不规则,可能是来自传入数据的计时错误。我真的很想只在我的 Api-Request 成功回复时才刷新。

NSString *entityDescription = @"Activity";
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityDescription inManagedObjectContext:weakSelf.managedObjectContext];
[fetchRequest setEntity:entity];

NSError *error;
NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

for (NSManagedObject *managedObject in items) 
    [self.managedObjectContext deleteObject:managedObject];

我将如何实现这一目标?

【问题讨论】:

你在那个代码之后保存了吗?您的实体是否有日期(例如下载日期)? 不,我没有保存。我会这样做的,谢谢。我在实体中也没有下载日期。这不是服务器提供给我的东西。从服务器获取数据后是否需要设置? 如果您想在收到回复后进行清除,您需要通过某种方式来区分什么是新的,什么是旧的...... 我可以记下进入 ViewContoller 的时间,任何旧的都被删除,而加载的任何东西都会获得一个新的当前时间戳 你可以,但你必须重新处理所有映射的项目,然后重新保存数据库。不是问题,而是麻烦。 【参考方案1】:

最简单的选择是在应用启动时从磁盘中删除 Core Data 存储文件并创建一个新文件。这显然不适用于在请求返回良好数据之前保留数据。

为此,您需要能够分辨什么是旧的,什么是新的。 RestKit 可以为您做到这一点,但如果您正在加载分页数据,它将无法正常工作(当您获得新页面时,它往往会删除您拥有的页面)。

您可以使用与您所拥有的代码类似的代码(应该可以),但在请求的 success 块中。在success 块中,您拥有所有新项目,因此您只需检查它是否是第一个请求(BOOL 实例变量),如果是,则删除不在mappingResult 中的所有内容。

【讨论】:

最后一个解决方案是我想要的。在新数据到达之前,旧数据应该是可见的。谢谢。【参考方案2】:

我的情况非常相似,使用的是 RestKit 和 Core Data。远程数据始终是最新的源,因此我希望 Core Data “清除”远程数据库中不存在的内容。

我花了一段时间尝试做你想做的事 - 完全清除本地持久存储 - 我尝试的每一种方法似乎都会导致问题。

RestKit 具有内置功能,可以为您更新 CoreData 并删除 CoreData 中不再存在于远程数据源中的那些实体(或 API 不再为特定调用返回的实体)。

它被称为“获取请求块”。

- (void)setupFetchRequestBlocksForObjectManager:(RKObjectManager*)manager

    [manager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) 
        RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"article"];

        NSDictionary *argsDict = nil;
        BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];
        if (match) 
            NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
            fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"articleId" ascending:YES] ];
            return fetchRequest;
        
        return nil;
    ];

在这个例子中,我描述了这个 Fetch Request Block 所针对的 API 调用,然后描述了应该匹配它的 CoreData 请求。任何与 API 调用返回的对象不同的 Core Data 对象都将被更改/删除。

这个例子是一个非常简单的 API 调用,但你也可以在匹配器中包含参数,以便它只匹配更复杂的请求 - there's a good example of that on the RestKit site.

还有一个关于 SO 的问题here.

【讨论】:

您是否在 RKPaginator 中使用此示例?加载第二页笔记会导致第一页的数据被删除吗? 我没有使用 RKPaginator,但我已经尝试使用分页 API 调用。您必须小心 NSFetchRequest 返回与您正在调用的 URL(包括参数)相同的页面 - 这是一个正确的“匹配”。链接中的示例在匹配请求的参数方面做得更多。这样做当然更复杂,但这就是这些 Fetch Request Blocks 的用途,希望对 RKPaginator 的支持会更好(如果它还没有 - 如果我错了,请纠正我)。 我设法从 Wain 那里得到了一个很好的例子,所以目前我会坚持下去。但是当我有更多时间时,我会尝试获取请求块,因为我想尽可能多地学习 RestKit 技术。当我走到那一步时,我会再次发布。感谢您的信息。

以上是关于用新的核心数据初始化 RestKit 的 RKPaginator的主要内容,如果未能解决你的问题,请参考以下文章

使用 RestKit 0.20 初始化核心数据

Restkit 从核心数据中删除项目

RestKit 核心数据集成

使用 RestKit 0.20 备份核心数据

RestKit 核心数据'managedObjectStore 为零'

Restkit核心数据明细数据