使用NSPredicate检查实体在插入数据时是否已包含值

时间:2012-01-11 09:59:55

标签: iphone xcode cocoa-touch core-data nspredicate

我需要将大量的json提要存储到Core Data中。有太多的Feed,我无法一次性调用它们,因为加载应用程序需要很长时间。因此,当应用程序启动时,我会调用最重要的应用程序,并将其余部分分配到整个应用程序中。但是,我还需要将这些存储到Core Data中。

第一个视图只是一个tableview,其中包含名称。当您单击某个名称时,您将被发送到下一个视图,其中应该有一些文本和一些图片。因此,当加载第二个视图时,我向Web服务发送请求并将该服务的答案存储在Core Data中。

如果您单击两次相同的tableviewcell,则所调用的服务中的信息将被写入Core Data两次,从而创建重复值。我想避免这种情况。

我想要做的是检查我的实体是否已包含其中一个唯一值。如果是,请不要存储在Core Data中。如果没有,请存储它。

这是我的方法:

-(void)addImage:(NSManagedObjectContext *)context withImageUrl:(NSString *)imageUrl{
NSFetchedResultsController *fetchedResultsController = [self fetchObjectsFromEntity:@"Image" withContext:context andSortKey:@"imageUrl"];

[fetchedResultsController.fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"imageUrl contains[cd] %@" , imageUrl]];


if (//WHAT TO PUT HERE?) {
    NSLog(@"Doesn't exist");
    Image *image = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:context];
    image.imageUrl = imageUrl;
}else{
    NSLog(@"Already exists");
}


-(NSFetchedResultsController *)fetchObjectsFromEntity:(NSString *)entityName withContext:(NSManagedObjectContext *)context andSortKey:(NSString *)key{
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
[fetchRequest setEntity:entity];

if (key != nil) {

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey:key ascending:YES];
    NSArray *sortDescs = [[NSArray alloc]initWithObjects:sortDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescs];
}

NSFetchedResultsController *fetchedResultController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:@"Root"];

if (![fetchedResultController performFetch:&error]) {
    NSLog(@"Error: %@" , error);
}          

    return fetchedResultController;
}

有没有人知道如何实现这一目标?谓词错了吗?如何检查谓词是否为真?

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

你正在做的事情会非常昂贵。您必须记住,每次执行NSFetchRequest时,您将执行SQL(昂贵)并执行I / O(也很昂贵)。您的目标是限制您执行此操作的次数。

如果您可以获得(例如10个)唯一键的列表(在您的情况下是imageURL),然后执行获取请求以查看这些imageURL中哪些已经存储在商店中,那将会便宜很多(a在这种情况下,因子约为10)。

此外,由于您对实际对象不感兴趣,只是它们是否存在,您应该将获取请求的resultType设置为NSDictionaryResultType并将propertiesToFetch设置为包含只是你的关键词[NSArray arrayWithObject:@"imageUrl"]

最后,比较字符串非常昂贵。尽量不要使用@"imageUrl contains[cd] %@"。它要求数据库做很多工作。如果你有一些数字键,例如一个64位的数字,这将使事情变得更快,因为你可以使用数字比较。

将所有这些放在一起,我们假设您的唯一键属性称为uniqueID。您可以像这样运行提取请求

- (NSArray *)keysMissingInStoreFromKeys:(NSArray *)someKeys;
{
    NSFetchRequest *r = [NSFetchRequest fetchRequestWithEntityName:@"Image"];
    [r setResultType:NSDictionaryResultType];
    [r setPropertiesToFetch:[NSArray arrayWithObject:@"uniqueID"];
    NSPredicate *p = [NSPredicate predicateWithFormat:@"uniqueID IN %@", someKeys];
    [r setPredicate:p];
    NSError *error = nil;
    NSArray *result = [moc executeFetchRequest:r error:&error];
    NSAssert(result != nil, @"Fetch failed: %@", error);
    NSMutableArray *missingKeys = [someKeys mutableCopy];
    for (NSDictionary *values in result) {
        id uniqueID = [values objectForKey:@"uniqueID"];
        [missingKeys removeObject:uniqueID];
    }
    return missingKeys;
}

希望这有帮助。