IOS核心数据 - 查找或创建重复插入

时间:2014-04-21 02:59:32

标签: ios core-data sync nsmanagedobject

在尝试将网络服务数据与本地商店同步时,我在逻辑中遗漏了一些东西,我需要你的帮助。这就是我所拥有的:

我有一个NSArray NSDictionaries描述每个事件对象(从网上下载),我按事件ID排序。然后我使用IN谓词获取本地存储,并按事件ID对其进行排序。然后我尝试迭代并匹配id,如果匹配,我更新记录,如果他们不匹配,我创建新的NSManagedObject。如果新下载的事件对象的eventID比本地存储中的最后一个eventID更大,则它可以正常工作,但如果来自Web服务的eventID小于本地存储中的eventID,那么 INSERTS ALL OBJECTS ,无论如何如果他们存在或不存在,那确实是我的问题。

所以换句话说,如果新记录位于排序数组的开头,它将添加每个对象,但如果它位于排序数组的末尾,它将更新除新记录之外的所有对象。我需要它来创建新的并更新旧的。

这里有一些代码:

具有逻辑的功能,我相信我错过了一些东西:

- (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方法。

如果您有任何其他问题,请告诉我。

2 个答案:

答案 0 :(得分:1)

试试这个,

- (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 {
        .....
    }
}

答案 1 :(得分:0)

我认为,每次插入新的事件对象时,都应该更新storedObjects,使其现在应该包含插入的对象。 或者更简单地说,您应该将storedObjects的初始化行放在for循环中。 (这样可以确保从downloadedObjects开头枚举每个eventObject的{​​{1}}上的索引与storedObjects上的索引相同。但是,关于您的代码,这只会是如果storedObjects中的所有元素总是在downloadedObjects中找到,我认为是这种情况,则为true。)

但有一件事,fetchedRecords应该与storedObjects相同,如果它们是你应该将storedObjects重新分配为[self.fetchedResultsController fetchedObjects],因为它会反映变化在您的上下文中,不执行另一个获取请求,这将解决上述建议的低效率。