使用 RestKit+CoreData 时,如何只获取从服务器发送和映射回的对象行?
How can I fetch only object rows sent&mapped back from server when using RestKit+CoreData?
我正在使用 RestKit 0.2.x 和 Core Data 并遵循标准教程,即:
- 创建核心数据模型并使用
mogenerator
编写代码
- 用基础实例化对象管理器URL
- 创建托管对象上下文和持久存储
- 为我的网络服务返回的所有实体创建实体映射
- 为所有网络服务端点和实体创建响应描述符
- 向对象管理器添加响应描述符
一切似乎都"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
- 如果可以的话,请告诉我怎么做!!! - 这样我的问题就解决了,我可以享受缓存而不必担心我的过滤器是否被忽略了。
我不是想做的,然而,是这样的:
- 用
parameters
and/or path
调用 getObjectsAtPath: parameters: success: failure:
代表一种 "server-side" 谓词
- 成功后,创建一个
NSFetchRequest
和一个反映我的服务器端谓词的客户端谓词
这种方法看起来真的很愚蠢,但是,我不知道更好的方法。但我拒绝这样做。它容易出错、冗余并且可能会占用大量资源。
因此,我选择在调用 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" 谓词客户端 NSPredicate
s.
关于这应该如何工作,我错过了什么?显然,我错过了一些重要的东西。
If I then blindly follow the tutorials
从来都不是一个好主意,您需要利用从教程中学到的知识并将其应用到您的问题中space。
当您使用 Core Data 时,这些项目确实会保留下来。您不需要,但它确实有助于内存管理。从技术上讲,您不需要 运行 获取,因为映射结果 (RKMappingResult
) 包含所有映射的对象,因此您可以提取它们并传递它们。
您回避 运行 使用过滤器进行本地提取的另一种方法实际上是完全可以接受的,我想说这是通常的方法,因为它是基于提取结果控制器的方法的工作方式...方便您将查询参数添加到映射中,以便更新映射的对象。您确实需要谨慎,因为返回相同对象的多个请求可能会覆盖数据(假设您使用的是唯一标识符)。
我正在使用 RestKit 0.2.x 和 Core Data 并遵循标准教程,即:
- 创建核心数据模型并使用
mogenerator
编写代码 - 用基础实例化对象管理器URL
- 创建托管对象上下文和持久存储
- 为我的网络服务返回的所有实体创建实体映射
- 为所有网络服务端点和实体创建响应描述符
- 向对象管理器添加响应描述符
一切似乎都"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
- 如果可以的话,请告诉我怎么做!!! - 这样我的问题就解决了,我可以享受缓存而不必担心我的过滤器是否被忽略了。
我不是想做的,然而,是这样的:
- 用
parameters
and/orpath
调用getObjectsAtPath: parameters: success: failure:
代表一种 "server-side" 谓词 - 成功后,创建一个
NSFetchRequest
和一个反映我的服务器端谓词的客户端谓词
这种方法看起来真的很愚蠢,但是,我不知道更好的方法。但我拒绝这样做。它容易出错、冗余并且可能会占用大量资源。
因此,我选择在调用 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" 谓词客户端 NSPredicate
s.
关于这应该如何工作,我错过了什么?显然,我错过了一些重要的东西。
If I then blindly follow the tutorials
从来都不是一个好主意,您需要利用从教程中学到的知识并将其应用到您的问题中space。
当您使用 Core Data 时,这些项目确实会保留下来。您不需要,但它确实有助于内存管理。从技术上讲,您不需要 运行 获取,因为映射结果 (RKMappingResult
) 包含所有映射的对象,因此您可以提取它们并传递它们。
您回避 运行 使用过滤器进行本地提取的另一种方法实际上是完全可以接受的,我想说这是通常的方法,因为它是基于提取结果控制器的方法的工作方式...方便您将查询参数添加到映射中,以便更新映射的对象。您确实需要谨慎,因为返回相同对象的多个请求可能会覆盖数据(假设您使用的是唯一标识符)。