Вопрос

I'm using Core Data to cache data, here is my code to insert object:

//data array count is 15
for (NSDictionary *dictionary in dataArray)
{
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"CacheData" inManagedObjectContext:context];
    [request setEntity:entity];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"title LIKE '%@'",dictionary[@"title"]];
    [request setPredicate:predicate];
    NSArray *fetchArray = [context executeFetchRequest:request error:NULL];

    if ([fetchArray count] == 0)
    {
        CacheData *cacheData = [NSEntityDescription insertNewObjectForEntityForName:@"CacheData" inManagedObjectContext:context];
        [cacheData setTitle:dictionary[@"title"]];
        [cacheData setLink:dictionary[@"link"]];
        [cacheData setPublishDate:dictionary[@"pubDate"]];

        NSError *insertError = nil;
        if (![context save:&insertError])
        {
            return NO;
        }
    }
}

The count of dataArray is 15, so I should insert 15 items to Core Data. But once I used NSFetchRequest to fetch items, the array count returned added 1, and become 16, and fetch items again, it added 1 to 17 again:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"CacheData" inManagedObjectContext:[[CacheDataManagement sharedInstance] managedObjectContext]];
[request setEntity:entity];
NSArray *fetchArray = [[[CacheDataManagement sharedInstance] managedObjectContext] executeFetchRequest:request error:NULL];
for (CacheData *data in fetchArray) {
    NSLog(@"fetch:%@",[data title]);
}

NSLog(@"%ld",[fetchArray count]);  //fetch array count is 16

Something wrong with my code ?

Update

Changed if ([fetchArray count] != 0) { … } to if ([fetchArray count] == 0) { … }

Это было полезно?

Решение

Since the problem it's not quite clear to me (I would like to have more details), I'll try to give you some hints.

First, the save should be done outside the for loop (In addition it's not correct to do a return within it).

// for in loop here    

NSError *insertError = nil;
if (![context save:&insertError]) {
    NSLog("%@", insertError);
    return NO; // do it if the method you are running in returns a bool
}

Second, to check for duplicated you should rely on a GUID but if don't have it the predicate should look like the following.

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"title == %@",dictionary[@"title"]];

Third, also the execute for executeFetchRequest:error: should be replace with countForFetchRequest:error: since you don't need to return the objects but only a count. According to Apple doc, it

Returns the number of objects a given fetch request would have returned if it had been passed to executeFetchRequest:error:.

Finally, in the for loop you are executing a request each time. My suggestion is to move execute a request before the loop and then checking for results within it. This according to Implementing Find-or-Create Efficiently. In this case, the pattern will enforce you to have a GUID for you entity.

Obviously, these are just hints. The real way to find the problem is to debug. In addition, I will perform tests starting from a fresh environment, i.e. the app has been deleted from the simulator or device.

Другие советы

In your code [fetchArray count] != 0 checks the inserting data is already exists. Try changing it like

if ([fetchArray count] == 0)
{
     CacheData *cacheData = [NSEntityDescription insertNewObjectForEntityForName:@"CacheData" inManagedObjectContext:context];
     [cacheData setTitle:dictionary[@"title"]];
     [cacheData setLink:dictionary[@"link"]];
     [cacheData setPublishDate:dictionary[@"pubDate"]];

     NSError *insertError = nil;
     if (![context save:&insertError])
     {
         return NO;
     }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top