Restkit 本地数据映射操作似乎没有保存到磁盘
Restkit local data mapping operation doesn't seem to save to disk
我目前使用的是 RestKit 版本 0.26.0
。
我正在执行本地映射操作(它需要一个本地 .json 文件,并将其解析为 objective c 核心数据对象)。我是这样做的:
/*
From:
*/
NSString* const MIMEType = @"application/json";
NSString* resourceName = [route.pathPattern stringByReplacingOccurrencesOfString:@"/" withString:@"--"];
NSString* data_filePath = [[NSBundle mainBundle] pathForResource:resourceName ofType:@"json"];
NSData *data = [NSData dataWithContentsOfFile:data_filePath];
NSError* error = nil;
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:MIMEType error:&error];
if (parsedData == nil && error) {
// Parser error...
}
RKManagedObjectStore *managedObjectStore = self.objectManager.managedObjectStore;
RKManagedObjectMappingOperationDataSource *mappingDataSource = [[RKManagedObjectMappingOperationDataSource alloc]
initWithManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext
cache:managedObjectStore.managedObjectCache];
static NSMutableArray<RKMapperOperation*>* mapperOperations;
if (mapperOperations == nil)
{
mapperOperations = [NSMutableArray array];
}
RKMapperOperation* mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:parsedData
mappingsDictionary:objectMappings];
[mapperOperation setMappingOperationDataSource:mappingDataSource];
[mapperOperations addObject:mapperOperation];
dispatch_async(dispatch_get_main_queue(), ^{
NSError *mappingError = nil;
BOOL isMapped = [mapperOperation execute:&mappingError];
if (isMapped && !mappingError)
{
success(mapperOperation,mapperOperation.mappingResult);
}
else
{
failure(mapperOperation,mappingError,false);
}
NSUInteger mapperOperation_index = [mapperOperations indexOfObject:mapperOperation];
BOOL remove_mapperOperation = (mapperOperation_index < mapperOperations.count);
NSCAssert(remove_mapperOperation, @"unhandled");
if (remove_mapperOperation)
{
[mapperOperations removeObjectAtIndex:mapperOperation_index];
}
});
return mapperOperation;
当请求到达其成功块时,一切似乎都井井有条——我按照我想要的方式解析了所有对象,并通过了映射结果。不仅如此,我还能够使用 NSFetchRequest
和我的 RKObjectManager
的 managedObjectStore.mainQueueManagedObjectContext
获取这些对象。例如,以下 return 是我的身份验证令牌:
-(QDAuthenticationToken*)fetchAuthenticationTokenFromStore
{
NSManagedObjectContext* context = [QDNetworkManager sharedInstance].objectManagerMainQueueManagedObjectContext;
__block QDAuthenticationToken* authenticationToken = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest new];
[fetchRequest setFetchLimit:1];
[fetchRequest setEntity:[QDAuthenticationToken entityInManagedObjectContext:context]];
[context performBlockAndWait:^{
NSError* fetchError = nil;
NSArray* fetchedObjects = [context executeFetchRequest:fetchRequest error:&fetchError];
kRUConditionalReturn(fetchError != nil, YES);
kRUConditionalReturn(fetchedObjects.count != 1, NO);
authenticationToken = kRUClassOrNil(fetchedObjects.firstObject, QDAuthenticationToken);
}];
return authenticationToken;
}
此方法将可靠地 return 我在核心数据中拥有的 QDAuthenticationToken
的单个实例,在我在应用程序的生命周期中将一个实例映射到核心数据之后。不幸的是,一旦我终止了该应用程序并尝试上述获取,它就会 returns nil.
虽然肯定还有其他可能的解释,但这让我相信这些 RKMapperOperation
实例没有成功地将这些对象写入磁盘。有人可以提供任何帮助吗?
我也可以提供设置 RKObjectManager
的代码,但我在其他几个项目中使用了 restkit,设置代码完全相同,所以我非常怀疑问题出在我对对象的设置上经理。
**** 更新正确答案,感谢 Wain 的评论 ****
/*
From:
*/
NSString* const MIMEType = @"application/json";
NSString* resourceName = [route.pathPattern stringByReplacingOccurrencesOfString:@"/" withString:@"--"];
NSString* data_filePath = [[NSBundle mainBundle] pathForResource:resourceName ofType:@"json"];
NSData *data = [NSData dataWithContentsOfFile:data_filePath];
NSError* error = nil;
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:MIMEType error:&error];
if (parsedData == nil && error) {
// Parser error...
}
RKManagedObjectStore *managedObjectStore = self.objectManager.managedObjectStore;
NSManagedObjectContext* context = managedObjectStore.mainQueueManagedObjectContext;
RKManagedObjectMappingOperationDataSource *mappingDataSource = [[RKManagedObjectMappingOperationDataSource alloc]
initWithManagedObjectContext:context
cache:managedObjectStore.managedObjectCache];
static NSMutableArray<RKMapperOperation*>* mapperOperations;
if (mapperOperations == nil)
{
mapperOperations = [NSMutableArray array];
}
RKMapperOperation* mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:parsedData
mappingsDictionary:objectMappings];
[mapperOperation setMappingOperationDataSource:mappingDataSource];
@synchronized(mapperOperations) {
[mapperOperations addObject:mapperOperation];
}
dispatch_async(dispatch_get_main_queue(), ^{
__block BOOL operationSuccess = false;
__block NSError* operationError = nil;
[context performBlockAndWait:^{
NSError *mappingError = nil;
BOOL isMapped = [mapperOperation execute:&mappingError];
if ((isMapped == false) ||
(mappingError != nil))
{
operationError = mappingError;
return;
}
NSError* saveError = nil;
BOOL saveSuccess = [context saveToPersistentStore:&saveError];
if ((saveSuccess == false) ||
(saveError != nil))
{
operationError = saveError;
return;
}
operationSuccess = YES;
}];
if ((operationSuccess == TRUE) &&
(operationError == nil))
{
success(mapperOperation,mapperOperation.mappingResult);
}
else
{
failure(mapperOperation,operationError,false);
}
@synchronized(mapperOperations) {
NSUInteger mapperOperation_index = [mapperOperations indexOfObject:mapperOperation];
BOOL remove_mapperOperation = (mapperOperation_index < mapperOperations.count);
NSCAssert(remove_mapperOperation, @"unhandled");
if (remove_mapperOperation)
{
[mapperOperations removeObjectAtIndex:mapperOperation_index];
}
}
});
return mapperOperation;
RKMapperOperation
对上下文或保存上下文一无所知。当你执行操作时,执行一个映射,仅此而已。
RKManagedObjectMappingOperationDataSource
创建对象并在请求时将它们插入到上下文中。然后,这些对象在映射期间由 RKMapperOperation
更新。之后不要求数据源保存 - 数据源或映射器操作不负责在完成后进行保存。
因此,您需要在映射器操作完成后显式保存上下文(并且,根据您使用的上下文,保存任何父项)。
您的提取请求工作正常,因为它不需要在 returns 个对象之前保存上下文。
我目前使用的是 RestKit 版本 0.26.0
。
我正在执行本地映射操作(它需要一个本地 .json 文件,并将其解析为 objective c 核心数据对象)。我是这样做的:
/*
From:
*/
NSString* const MIMEType = @"application/json";
NSString* resourceName = [route.pathPattern stringByReplacingOccurrencesOfString:@"/" withString:@"--"];
NSString* data_filePath = [[NSBundle mainBundle] pathForResource:resourceName ofType:@"json"];
NSData *data = [NSData dataWithContentsOfFile:data_filePath];
NSError* error = nil;
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:MIMEType error:&error];
if (parsedData == nil && error) {
// Parser error...
}
RKManagedObjectStore *managedObjectStore = self.objectManager.managedObjectStore;
RKManagedObjectMappingOperationDataSource *mappingDataSource = [[RKManagedObjectMappingOperationDataSource alloc]
initWithManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext
cache:managedObjectStore.managedObjectCache];
static NSMutableArray<RKMapperOperation*>* mapperOperations;
if (mapperOperations == nil)
{
mapperOperations = [NSMutableArray array];
}
RKMapperOperation* mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:parsedData
mappingsDictionary:objectMappings];
[mapperOperation setMappingOperationDataSource:mappingDataSource];
[mapperOperations addObject:mapperOperation];
dispatch_async(dispatch_get_main_queue(), ^{
NSError *mappingError = nil;
BOOL isMapped = [mapperOperation execute:&mappingError];
if (isMapped && !mappingError)
{
success(mapperOperation,mapperOperation.mappingResult);
}
else
{
failure(mapperOperation,mappingError,false);
}
NSUInteger mapperOperation_index = [mapperOperations indexOfObject:mapperOperation];
BOOL remove_mapperOperation = (mapperOperation_index < mapperOperations.count);
NSCAssert(remove_mapperOperation, @"unhandled");
if (remove_mapperOperation)
{
[mapperOperations removeObjectAtIndex:mapperOperation_index];
}
});
return mapperOperation;
当请求到达其成功块时,一切似乎都井井有条——我按照我想要的方式解析了所有对象,并通过了映射结果。不仅如此,我还能够使用 NSFetchRequest
和我的 RKObjectManager
的 managedObjectStore.mainQueueManagedObjectContext
获取这些对象。例如,以下 return 是我的身份验证令牌:
-(QDAuthenticationToken*)fetchAuthenticationTokenFromStore
{
NSManagedObjectContext* context = [QDNetworkManager sharedInstance].objectManagerMainQueueManagedObjectContext;
__block QDAuthenticationToken* authenticationToken = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest new];
[fetchRequest setFetchLimit:1];
[fetchRequest setEntity:[QDAuthenticationToken entityInManagedObjectContext:context]];
[context performBlockAndWait:^{
NSError* fetchError = nil;
NSArray* fetchedObjects = [context executeFetchRequest:fetchRequest error:&fetchError];
kRUConditionalReturn(fetchError != nil, YES);
kRUConditionalReturn(fetchedObjects.count != 1, NO);
authenticationToken = kRUClassOrNil(fetchedObjects.firstObject, QDAuthenticationToken);
}];
return authenticationToken;
}
此方法将可靠地 return 我在核心数据中拥有的 QDAuthenticationToken
的单个实例,在我在应用程序的生命周期中将一个实例映射到核心数据之后。不幸的是,一旦我终止了该应用程序并尝试上述获取,它就会 returns nil.
虽然肯定还有其他可能的解释,但这让我相信这些 RKMapperOperation
实例没有成功地将这些对象写入磁盘。有人可以提供任何帮助吗?
我也可以提供设置 RKObjectManager
的代码,但我在其他几个项目中使用了 restkit,设置代码完全相同,所以我非常怀疑问题出在我对对象的设置上经理。
**** 更新正确答案,感谢 Wain 的评论 ****
/*
From:
*/
NSString* const MIMEType = @"application/json";
NSString* resourceName = [route.pathPattern stringByReplacingOccurrencesOfString:@"/" withString:@"--"];
NSString* data_filePath = [[NSBundle mainBundle] pathForResource:resourceName ofType:@"json"];
NSData *data = [NSData dataWithContentsOfFile:data_filePath];
NSError* error = nil;
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:MIMEType error:&error];
if (parsedData == nil && error) {
// Parser error...
}
RKManagedObjectStore *managedObjectStore = self.objectManager.managedObjectStore;
NSManagedObjectContext* context = managedObjectStore.mainQueueManagedObjectContext;
RKManagedObjectMappingOperationDataSource *mappingDataSource = [[RKManagedObjectMappingOperationDataSource alloc]
initWithManagedObjectContext:context
cache:managedObjectStore.managedObjectCache];
static NSMutableArray<RKMapperOperation*>* mapperOperations;
if (mapperOperations == nil)
{
mapperOperations = [NSMutableArray array];
}
RKMapperOperation* mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:parsedData
mappingsDictionary:objectMappings];
[mapperOperation setMappingOperationDataSource:mappingDataSource];
@synchronized(mapperOperations) {
[mapperOperations addObject:mapperOperation];
}
dispatch_async(dispatch_get_main_queue(), ^{
__block BOOL operationSuccess = false;
__block NSError* operationError = nil;
[context performBlockAndWait:^{
NSError *mappingError = nil;
BOOL isMapped = [mapperOperation execute:&mappingError];
if ((isMapped == false) ||
(mappingError != nil))
{
operationError = mappingError;
return;
}
NSError* saveError = nil;
BOOL saveSuccess = [context saveToPersistentStore:&saveError];
if ((saveSuccess == false) ||
(saveError != nil))
{
operationError = saveError;
return;
}
operationSuccess = YES;
}];
if ((operationSuccess == TRUE) &&
(operationError == nil))
{
success(mapperOperation,mapperOperation.mappingResult);
}
else
{
failure(mapperOperation,operationError,false);
}
@synchronized(mapperOperations) {
NSUInteger mapperOperation_index = [mapperOperations indexOfObject:mapperOperation];
BOOL remove_mapperOperation = (mapperOperation_index < mapperOperations.count);
NSCAssert(remove_mapperOperation, @"unhandled");
if (remove_mapperOperation)
{
[mapperOperations removeObjectAtIndex:mapperOperation_index];
}
}
});
return mapperOperation;
RKMapperOperation
对上下文或保存上下文一无所知。当你执行操作时,执行一个映射,仅此而已。
RKManagedObjectMappingOperationDataSource
创建对象并在请求时将它们插入到上下文中。然后,这些对象在映射期间由 RKMapperOperation
更新。之后不要求数据源保存 - 数据源或映射器操作不负责在完成后进行保存。
因此,您需要在映射器操作完成后显式保存上下文(并且,根据您使用的上下文,保存任何父项)。
您的提取请求工作正常,因为它不需要在 returns 个对象之前保存上下文。