使用 RestKit+CoreData 时,如何只获取从服务器发送和映射回的对象行?

How can I fetch only object rows sent&mapped back from server when using RestKit+CoreData?

我正在使用 RestKit 0.2.x 和 Core Data 并遵循标准教程,即:

一切似乎都"working"就好了...我可以打电话给

[[RKObjectManager sharedManager] getObjectsAtPath:_requestPath parameters:_requestParameters success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    [self requestSuccess];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    [self requestError:error];
}];

...一整天,然后我继续处理(如教程所示)

- (void)requestSuccess {
    NSManagedObjectContext *managedObjectContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:_entityName];
    fetchRequest.sortDescriptors = @[_defaultSortDescriptor];

    NSError *error = nil;
    requestData = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

    [_delegate handleRequestSuccess:self withData:requestData];
    //[self cleanupRequestBeforeSuccessWithData:requestData];
    [self completeRequest];
}

现在的问题是,至少在默认情况下,RestKit+CoreData 实际上将 GET 对象保存到它自己的持久性存储区,或类似的东西。我稍后会解释 "cleanupRequest..."。

这违背了试图允许用户在 Web 服务客户端级别指定参数的目的,因为所有对象似乎最终都在同一个地方。

例如,假设我有一个方法 /api/endpoint?queryString,我用两组不同的参数调用它:

[[RKObjectManager sharedManager] getObjectsAtPath:@"/api/endpoint" parameters:PARAMS_ONE success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    [self requestSuccess];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    [self requestError:error];
}];

[[RKObjectManager sharedManager] getObjectsAtPath:@"/api/endpoint" parameters:PARAMS_TWO success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    [self requestSuccess];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    [self requestError:error];
}];

如果我随后盲目地按照有关如何检索我的对象的教程进行操作,那么我的回调将完全相同!

NSManagedObjectContext *managedObjectContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"EndpointDataTransferObject"];
fetchRequest.sortDescriptors = @["endpointDataTransferObjectID"];

NSError *error = nil;
requestData = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

当然,结果是我的 delegate 在第一次调用时被发送(伪代码)requestData WHERE PARAMS_ONE,然后在第二次调用时 requestData WHERE PARAMS_ONE UNION requestData WHERE PARAMS_TWO

现在我真正想要的是能够对 仅那些从 Web 服务映射的项目执行 NSFetchRequest 我认为这是一个完全合理的期望,很明显我遗漏了一些东西,因为写这个库的人比我聪明得多。

例如,如果我能以某种方式从 success(RKRequestRequestOperation *o, RKMappingResult *m) 中提供的两个参数中获取所有对象的 NSArray - 如果可以的话,请告诉我怎么做!!! - 这样我的问题就解决了,我可以享受缓存而不必担心我的过滤器是否被忽略了。

不是想做的,然而,是这样的:

这种方法看起来真的很愚蠢,但是,我不知道更好的方法。但我拒绝这样做。它容易出错、冗余并且可能会占用大量资源。

因此,我选择在调用 completion:

之前在 success 回调的末尾添加一个小方法 cleanupRequestBeforeSuccessWithData
- (void)cleanupRequestBeforeSuccessWithData:(NSArray *)managedObjects {
    NSManagedObjectContext *managedObjectContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;

    for (NSManagedObject *o in managedObjects) {
        [managedObjectContext deleteObject:o];
    }

    NSError *error = nil;
    [managedObjectContext save:&error];
}

这很丑陋,但确实可以完成工作。现在它完全清空了缓存,但我宁愿不得不一遍又一遍地发出请求,而不是用 URL 的 然后 形式形成 "server-side" 谓词客户端 NSPredicates.

关于这应该如何工作,我错过了什么?显然,我错过了一些重要的东西。

If I then blindly follow the tutorials

从来都不是一个好主意,您需要利用从教程中学到的知识并将其应用到您的问题中space。

当您使用 Core Data 时,这些项目确实会保留下来。您不需要,但它确实有助于内存管理。从技术上讲,您不需要 运行 获取,因为映射结果 (RKMappingResult) 包含所有映射的对象,因此您可以提取它们并传递它们。

您回避 运行 使用过滤器进行本地提取的另一种方法实际上是完全可以接受的,我想说这是通常的方法,因为它是基于提取结果控制器的方法的工作方式...方便您将查询参数添加到映射中,以便更新映射的对象。您确实需要谨慎,因为返回相同对象的多个请求可能会覆盖数据(假设您使用的是唯一标识符)。