在 RestKit 0.20.2 中创建的重复核心数据对象

Posted

技术标签:

【中文标题】在 RestKit 0.20.2 中创建的重复核心数据对象【英文标题】:Duplicate Core Data objects created in RestKit 0.20.2 【发布时间】:2013-06-09 05:10:39 【问题描述】:

我遇到了一个问题,每次在 RestKit 0.20.2 中执行映射操作时,我都会对我的 SQLite 数据库进行重复写入。我在网上进行了相当广泛的研究,似乎找不到与我遇到的问题重复的问题——我看到的所有类似问题都集中在使用 RestKit 处理所有问题,而我只使用 RestKit 进行映射和数据库操作,因为我在另一个库中做网络方面的工作。

我有一个唯一的 identificationAttribute 属性集(推文 ID),并且我使用的是用 RKInMemoryManagedObjectCache 初始化的 managedObjectCache;但是,每次我执行映射操作时,我都会在所有内容上得到全面的重复。我用于网络端的库 (STTwitter) 将 JSON 作为数组返回,因此我遍历数组中的每个对象。还有其他一些我应该执行的操作吗?我的印象是 RestKit 在进行任何插入之前会将映射对象中指定的 identificationAttribute 属性与 SQLite 数据库中已有的属性进行比较。当我使用 RKManagedObjectRequestOperation 将它用于另一个项目中的所有内容时,我没有遇到这个问题。

这是我设置模型的方法:

-(void)setup

self.objectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[self managedObjectModel]];

[self.objectStore createPersistentStoreCoordinator];

NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"FoodTruckxxx.sqlite"];
NSLog(@"Setting up store at %@", path);
[self.objectStore addSQLitePersistentStoreAtPath:path
                          fromSeedDatabaseAtPath:nil
                               withConfiguration:nil
                                         options:self.optionsForSQLiteStore
                                           error:nil];

[self.objectStore createManagedObjectContexts];

self.objectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:self.objectStore.persistentStoreManagedObjectContext];

这是我执行映射操作的方式:

-(void)performMapping

int i = 0;
while (i < self.localCopyOfAllStatuses.count)

    RKManagedObjectStore *store = [[FoodTruckDataModel sharedDataModel] objectStore];
    RKEntityMapping *mapping = [ObjectMappings FoodTruckArticleMapping];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"FoodTruck" inManagedObjectContext:store.persistentStoreManagedObjectContext];
    NSManagedObject *newManagedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:store.persistentStoreManagedObjectContext];
    RKManagedObjectMappingOperationDataSource *mappingDS = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:store.persistentStoreManagedObjectContext cache:store.managedObjectCache];

    //assign new array to contain to just one object at a time and iterate through it
    NSArray *justOneStatus = [self.localCopyOfAllStatuses objectAtIndex:i];
    RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:justOneStatus destinationObject:newManagedObject mapping:mapping];
    operation.dataSource = mappingDS;
    NSError *error = nil;
    [operation performMapping:&error];
    [store.persistentStoreManagedObjectContext save:&error];
    [store.persistentStoreManagedObjectContext saveToPersistentStore:&error];
    i++;


这是映射:

+(RKEntityMapping *)FoodTruckArticleMapping

RKEntityMapping *jsonMapping = [RKEntityMapping mappingForEntityForName:@"FoodTruck" inManagedObjectStore:[[FoodTruckDataModel sharedDataModel] objectStore]];
jsonMapping.identificationAttributes = @[@"tweetID"];

[jsonMapping addAttributeMappingsFromDictionary:@
 @"text": @"tweet", @"user.screen_name": @"foodTruckName", @"created_at": @"timeStamp", @"id": @"tweetID"];

return jsonMapping;

而here 是我日志中的完整操作。任何帮助将不胜感激!

【问题讨论】:

您正在循环中显式创建托管对象实例。为什么不给 RestKit 整个 JSON 响应,让它完成所有的映射和​​对象创建? Wain- 我确实给了它 JSON 响应和 RKMappingOperation 中的映射,对吧? sourceObject 是 JSON 响应,mapping 是我的 RKEntityMapping。那么,除了NSManagedObject 之外,我会在那个电话中为destinationObject 添加什么? 【参考方案1】:

根据这个问题的答案on the RestKit Google Group board(我验证有效),解决方案是在我的RKMappingOperation 声明中不创建NSManagedObject 并将nil 分配给destinationObject。以下是此方法的正确代码,以及我最初问题的答案:

-(void)performMapping

    int i = 0;
    while (i < self.localCopyOfAllStatuses.count)
    
        RKManagedObjectStore *store = [[FoodTruckDataModel sharedDataModel] objectStore];
        RKEntityMapping *mapping = [ObjectMappings FoodTruckArticleMapping];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"FoodTruck" inManagedObjectContext:store.persistentStoreManagedObjectContext];
        RKManagedObjectMappingOperationDataSource *mappingDS = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:store.persistentStoreManagedObjectContext cache:store.managedObjectCache];

        //assign new array to contain to just one object at a time and iterate through it
        NSArray *justOneStatus = [self.localCopyOfAllStatuses objectAtIndex:i];
        RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:justOneStatus destinationObject:nil mapping:mapping];
        operation.dataSource = mappingDS;
        NSError *error = nil;
        [operation performMapping:&error];
        [store.persistentStoreManagedObjectContext save:&error];
        [store.persistentStoreManagedObjectContext saveToPersistentStore:&error];
        i++;
    

但是,RestKit Google Group 链接中也建议我实现 RKMapperOperation 而不是 RKMappingOperation,,因为这样可以省去我遍历 JSON 响应数组的麻烦。这是我最终使用的,为了提高效率和更好地使用 RestKit,我将其呈现:

-(void)performMapping

    RKManagedObjectStore *store = [[FoodTruckDataModel sharedDataModel] objectStore];
    RKManagedObjectMappingOperationDataSource *mappingDS = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:store.persistentStoreManagedObjectContext cache:store.managedObjectCache];
    RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:self.localCopyOfAllStatuses mappingsDictionary:@ [NSNull null]: [ObjectMappings FoodTruckArticleMapping] ];
    mapperOperation.mappingOperationDataSource = mappingDS;
    NSError *error = nil;
    [mapperOperation execute:&error];
    [store.persistentStoreManagedObjectContext save:&error];
    [store.persistentStoreManagedObjectContext saveToPersistentStore:&error];

【讨论】:

您为 [ObjectMappings FoodTruckArticleMapping] 提供的回报是什么,它只是地图的字典,还是包含关系映射等的 Mapper 对象……这是少数几个部分之一我正在努力解决问题。 [ObjectMappings FoodTruckArticleMapping] 是一个类方法,它实例化并返回一个RKEntityMapping 对象,该对象使用映射字典等进行初始化。如果您需要更多帮助,请告诉我;我可以为你在 Pastebin 或 Gist 上放一些代码。 如果你能告诉我你的 ObjectMappings 类会很棒,现在这对我来说更有意义,如果我正确理解这一点,那么在映射字典中,你可以放另一个 RKEntityMapping 如果你有嵌套实体。 给你:pastebin.com/dgFCjyxf。我没有做过嵌套实体,但应该有很多这样的例子。我还发现 RestKit 单元测试非常有用——你可以在他们的 GitHub 存储库中找到它们。 感谢代码片段,这几乎就是我现在所拥有的,虽然你为什么要调用 save: 和 saveToPersistentStore,不是默认版本之一,第二个是 RK 版本,但会写入 SQL 文件。一直在与编写 RK 的 BlakeWatter 交谈,他向我展示了 UT 类,我认为它与嵌套元素分开工作,只是一种预感....无法找到属性“”的嵌套值【参考方案2】:

目前,您正在循环中显式创建托管对象实例,因此 RestKit 没有机会检查重复项。相反,你应该给 RestKit 整个 JSON 响应,让它完成所有的映射和​​对象创建。

要实现这一点,请查看使用RKManagedObjectResponseMapperOperation。此操作允许您指定托管对象上下文、映射和整个响应内容(您无需显式执行任何循环)。这为 RestKit 提供了检查重复项所需的所有信息。

类似的东西:

RKManagedObjectResponseMapperOperation *responseMapperOperation = [[RKManagedObjectResponseMapperOperation alloc] initWithRequest:self.request
                                                                                                                         response:self.response
                                                                                                                             data:self.responseData
                                                                                                              responseDescriptors:self.responseDescriptors];
responseMapperOperation.mapperDelegate = self;
responseMapperOperation.managedObjectContext = self.managedObjectContext;
responseMapperOperation.managedObjectCache = self.managedObjectCache;

[responseMapperOperation setDidFinishMappingBlock:^(RKMappingResult *mappingResult, NSError *responseMappingError) 

    // use the mappingResult which contains the received objects

];

将 responseMapperOperation 添加到要执行的队列中。

请务必导入所需的 RestKit 类。

【讨论】:

Wain- 非常感谢您的回复。还要一两天我才能检查出来。 Wain- 你对我如何在我的代码中实现它有什么建议吗?另外,当我尝试直接使用它时,就像在RKManagedObjectResponseMapperOperation *rkTest = [[RKManagedObjectResponseMapperOperation alloc] init]; 中一样,它说它是一个未知的类型名称。谢谢! 感谢您的补充——您是希望我现在将其标记为答案还是等到我有时间实施它? 因此,在查看您的代码示例和 RestKit 文档时,RKManagedObjectResponseMapperOperation 初始化方法似乎需要 NSURLRequestNSHTTPURLResponse 对象...如问题所述,我使用另一个库(STTwitter)来执行所有的 REST 操作,所以我只是给 RestKit 一个 JSON 数组。有什么我遗漏的东西吗,或者有没有办法让这门课与它一起工作? 我希望你的图书馆比它有更多的访问权限。 RestKit 需要访问 URL 以便根据映射和配置的获取请求来处理 JSON。 performMappingOnResponseWithCompletionBlock: 有很多内容。您需要为此复制源代码并进行修改。但是您使用的库甚至没有给您 URL...

以上是关于在 RestKit 0.20.2 中创建的重复核心数据对象的主要内容,如果未能解决你的问题,请参考以下文章

核心数据。如何使用在 NSManagedObject 子类中创建的方法

在python中创建的文件应该打印错误消息[重复]

在 Windows 资源管理器中看不到在 android 中创建的文件 [重复]

我们如何在Android中重用已经在IOS中创建的Sqlite文件[重复]

引用在 AppDelegate 中创建的 NSPersistentStore 实例

Restkit 0.20:在自己的静态库中构建存档时找不到