Restkit本地数据映射操作似乎无法保存到磁盘

时间:2015-12-21 19:54:09

标签: ios core-data restkit

我目前正在使用RestKit版本0.26.0

我正在执行本地映射操作(它接受一个本地.json文件,并将其解析为目标c核心数据对象)。我是这样做的:

/*
 From:
 http://stackoverflow.com/questions/26556883/restkit-sync-data-base-with-local-json-file
 */
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;

当请求到达其成功块时,一切似乎都是有序的 - 我将所有对象解析为我想要的,通过映射结果。不仅如此,我还可以使用NSFetchRequestRKObjectManager managedObjectStore.mainQueueManagedObjectContext来获取这些对象。例如,以下内容返回我的身份验证令牌:

-(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;
}

在我在应用程序的生命周期中将一个映射到核心数据之后,此方法将可靠地返回我在核心数据中的QDAuthenticationToken单个实例。不幸的是,一旦我杀了应用程序并尝试上面的提取,它就会返回nil。

虽然肯定有其他可能的解释,但这让我相信这些RKMapperOperation实例并没有成功地将这些对象写入磁盘。任何人都可以提供任何帮助吗?

我也可以提供我的代码来设置RKObjectManager,但我在其他一些项目中使用restkit和完全相同的设置代码,所以我非常怀疑问题是我的对象管理器设置。

****更新正确答案,感谢Wain的评论****

/*
 From:
 http://stackoverflow.com/questions/26556883/restkit-sync-data-base-with-local-json-file
 */
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;

1 个答案:

答案 0 :(得分:1)

RKMapperOperation对上下文或保存环境一无所知。执行操作时,执行映射即可。

RKManagedObjectMappingOperationDataSource创建对象并在请求时将它们插入上下文中。然后在映射期间由RKMapperOperation更新这些对象。在此之后,数据源不会被要求保存 - 数据源或映射器操作的责任是在它们完成后保存。

因此,您需要在映射器操作完成后显式保存上下文(并且,具体取决于您使用的上下文,任何父项)。

您的获取请求正常,因为它不需要在返回对象之前保存上下文。