IOS核心数据-查找或创建重复插入
在尝试将web服务数据与本地存储同步时,我的逻辑中缺少了一些东西,我需要您的帮助。这就是我得到的: 我有一个IOS核心数据-查找或创建重复插入,ios,core-data,sync,nsmanagedobject,Ios,Core Data,Sync,Nsmanagedobject,在尝试将web服务数据与本地存储同步时,我的逻辑中缺少了一些东西,我需要您的帮助。这就是我得到的: 我有一个NSArray的nsdictionary描述每个事件对象(从web下载),我按事件id排序。然后我使用IN谓词获取本地存储,并按事件id排序。然后我尝试迭代和匹配id,如果它们匹配,我更新记录,如果它们不匹配,我将创建新的NSManagedObject。如果新下载的事件对象的eventID大于本地存储区中的最后一个eventID,则可以正常工作,但如果web服务中的eventID小于本地存
NSArray
的nsdictionary
描述每个事件对象(从web下载),我按事件id排序。然后我使用IN谓词获取本地存储,并按事件id排序。然后我尝试迭代和匹配id,如果它们匹配,我更新记录,如果它们不匹配,我将创建新的NSManagedObject
。如果新下载的事件对象的eventID大于本地存储区中的最后一个eventID,则可以正常工作,但如果web服务中的eventID小于本地存储区中的eventID,则它将插入所有对象,无论它们是否存在,这正是我的问题
换句话说,如果一条新记录位于排序数组的开头,它将添加所有对象,但如果它位于排序数组的末尾,它将更新除新记录之外的所有对象。我需要它来创建新的和更新旧的
下面是一些代码:
我认为我遗漏了一些东西的逻辑函数:
- (void)findOrCreateObject:(NSArray*)eventArray
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
//get sorted stored records
NSArray *fetchedRecords = [self.fetchedResultsController fetchedObjects];
//sort dictionaries
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:YES];
NSArray *downloadedRecords = [self.events sortedArrayUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
NSLog(@"DOWNLOADED EVENTS = %@", downloadedRecords);
NSLog(@"FETCHED EVENTS = %@", fetchedRecords);
//if store is not empty we need to walk through data and add/update records, otherwise/ELSE we need to import initial data
if (fetchedRecords.count != 0) {
//stores has records already
NSLog(@"FIND OR CREATE PROCESS");
if ([downloadedRecords count] > 0) {
NSArray *storedRecords = [self fetchEvents:eventArray withContext:context];
NSUInteger currentIndex = 0;
for (NSDictionary* event in downloadedRecords) {
Event* eventObject = nil;
if ([storedRecords count] > currentIndex) {
eventObject = [storedRecords objectAtIndex:currentIndex];
}
NSLog(@"STRING VALUE OF KEY = %@", [[eventObject valueForKey:@"eventID"]stringValue]);
if ([[event valueForKey:@"id"] isEqualToString:[[eventObject valueForKey:@"eventID"] stringValue]]) {
//Update Record
NSLog(@"Updating Record!!!");
[self updateManagedObject:eventObject withRecord:event inContext:context];
}
else
{
//New Record
NSLog(@"Inserting Record!!!");
eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:context];
eventObject.eventID = [self makeNumberFromString:[event valueForKey:@"id"]];
eventObject.title = [event valueForKey:@"title"];
eventObject.venue = [event valueForKey:@"venue"];
}
currentIndex++;
}
}
}
else
{
//import initial data
NSLog(@"IMPORTING INITIAL DATA");
for (NSDictionary* event in downloadedRecords) {
Event *eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:context];
eventObject.eventID = [self makeNumberFromString:[event valueForKey:@"id"]];
eventObject.title = [event valueForKey:@"title"];
eventObject.venue = [event valueForKey:@"venue"];
}
}
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
}
FETCHEVENTS方法:
-(NSArray*)fetchEvents:(NSArray*)eIDs withContext:(NSManagedObjectContext*)context
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(eventID IN %@)", eIDs];
[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:@[ [[NSSortDescriptor alloc] initWithKey: @"eventID" ascending:YES] ]];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(@"No rows returned");
}
return fetchedObjects;
}
更新对象方法:
- (void)updateManagedObject:(NSManagedObject*)object withRecord:(NSDictionary*)record inContext:(NSManagedObjectContext*)context
{
[object setValue:[self makeNumberFromString:[record valueForKey:@"id"]] forKey:@"eventID"];
[object setValue:[record valueForKey:@"title"] forKey:@"title"];
[object setValue:[record valueForKey:@"venue"] forKey:@"venue"];
}
下载web服务数据并对其进行解析后,我将调用findOrCreate方法
如果您有任何其他问题,请告诉我。我认为,每次插入新的事件对象时,您都应该更新
storedObjects
,以便它现在应该包含插入的对象。
或者更简单地说,您应该将storedObjects
的初始化行放在for循环中。(这将确保当您从downloadeobjects
开始枚举时,每个eventObject
上的索引都与storedObjects
上的索引相同。但是,对于您的代码而言,只有当storedObjects
的所有元素总是在downloadebjects
中找到时,这才是正确的。)嗯,我想是这样的。)
但是有一件事是不是fetchedRecords
应该与storedObjects
相同,如果它们是,您应该将storedObjects重新分配为[self.fetchedResultsController fetchedObjects]
,因为它将反映您上下文中的更改,而无需执行另一个获取请求,这将解决上述建议的低效性。试试这个
- (void)findOrCreateObject:(NSArray*)eventArray {
//if store is not empty we need to walk through data and add/update records, otherwise/ELSE we need to import initial data
if (fetchedRecords.count != 0) {
//stores has records already
NSLog(@"FIND OR CREATE PROCESS");
if ([downloadedRecords count] > 0) {
NSArray *storedRecords = [self fetchEvents:eventArray withContext:context];
for (NSDictionary* event in downloadedRecords) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"eventID = %@",[event valueForKey:@"id"]];
NSArray *matchedArray = [storedRecords filteredArrayUsing
Predicate:predicate];
Event* eventObject = nil;
if ([matchedArray count] > 0) {
//Update Record
NSLog(@"Updating Record!!!");
eventObject = [matchedArray objectAtIndex:0];
[self updateManagedObject:eventObject withRecord:event inContext:context];
}
else
{
//New Record
NSLog(@"Inserting Record!!!");
eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:context];
eventObject.eventID = [self makeNumberFromString:[event valueForKey:@"id"]];
eventObject.title = [event valueForKey:@"title"];
eventObject.venue = [event valueForKey:@"venue"];
}
}
}
} else {
.....
}
}
请进行更多的调试并编辑您的问题,以专门涵盖工作不正常的部分。工作正常。起初它对我不起作用,因为我的eventID是NSNumber,所以我总是得到空的匹配数组。我修好了,它成功了。谢谢,这意味着我将不得不对下载的数组中的每个对象进行提取,这是我不想做的。如果在一个数组中有数千个对象,那么它的效率很低,而且成本也很高。是的,这个答案非常简单。除了建议使用fetchresultscontroller之外,您还可以为storedObjects使用NSMutableArray,并在其中插入当前索引中新创建的eventObject,这不会影响此示例代码的效率