在 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 类,我认为它与嵌套元素分开工作,只是一种预感....无法找到属性“目前,您正在循环中显式创建托管对象实例,因此 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
初始化方法似乎需要 NSURLRequest
和 NSHTTPURLResponse
对象...如问题所述,我使用另一个库(STTwitter)来执行所有的 REST 操作,所以我只是给 RestKit 一个 JSON 数组。有什么我遗漏的东西吗,或者有没有办法让这门课与它一起工作?
我希望你的图书馆比它有更多的访问权限。 RestKit 需要访问 URL 以便根据映射和配置的获取请求来处理 JSON。 performMappingOnResponseWithCompletionBlock: 有很多内容。您需要为此复制源代码并进行修改。但是您使用的库甚至没有给您 URL...以上是关于在 RestKit 0.20.2 中创建的重复核心数据对象的主要内容,如果未能解决你的问题,请参考以下文章
核心数据。如何使用在 NSManagedObject 子类中创建的方法
在 Windows 资源管理器中看不到在 android 中创建的文件 [重复]
我们如何在Android中重用已经在IOS中创建的Sqlite文件[重复]