检查Core Data中是否存在对象的最快方法?

时间:2010-02-12 13:40:32

标签: objective-c iphone core-data

我想知道对象是否在Core Data中持久存在。例如,我在Core Data中有Friends,我通过firstName识别它们。我可以查询核心数据以查看“George”是否已知。如果结果集数组包含多个零对象,我知道George就在那里。但是核心数据将整个内容加载到内存中,我实际上只是想知道乔治是否存储。

我如何以最有效的方式做到这一点?

5 个答案:

答案 0 :(得分:96)

设置核心数据请求,而不是实际发出查询,请执行以下操作:

NSError *error = nil;
NSUInteger count = [managedObjectContext countForFetchRequest:request
                                                        error:&error];
if (!error) {
    return count;
} else {
  return 0;
}

实际上,方法countForFetchRequest:error:会返回给定获取请求传递给executeFetchRequest:error:时返回的对象数。


修改: (由Regexident提供)

正如 Josh Caswell 正确评论,处理错误的正确方法是:

if (count == NSNotFound) {
    NSLog(@"Error: %@", error);
    return 0;
}
return count;

或者此(没有错误记录):

return (count != NSNotFound) ? count : 0;

答案 1 :(得分:25)

是的,绝对有更好的方法。像往常一样设置一个获取请求,但是,如果它已经传递给executeFetchRequest,只需询问它将返回的对象数量:错误:

这可以使用

完成
- (NSUInteger)countForFetchRequest:(NSFetchRequest *)request error:(NSError **)error;

这样的事情:

- (int) numberOfContacts{

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSManagedObjectContext *managedObjectContext = yourManagedObjectContext;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:managedObjectContext];
    [request setEntity:entity];

    NSError *error = nil;
    NSUInteger count = [managedObjectContext countForFetchRequest:request error:&error];
    [request release];

    if (!error){
        return count;
    }
    else
        return -1;

}

答案 2 :(得分:7)

如果目标是检查对象是否存在,解决方案是在您的朋友模型中实现此方法:

-(BOOL)exist
{
    NSManagedObjectContext *managedObjectContext = yourManagedObjectContext;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Friends" inManagedObjectContext:managedObjectContext];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entity];
    [request setFetchLimit:1];
    [request setPredicate:[NSPredicate predicateWithFormat:@"firstName == %@", self.firstName]];    

    NSError *error = nil;
    NSUInteger count = [managedObjectContext countForFetchRequest:request error:&error];

    if (count)
    {
        return YES;
    }
    else
    {
        return NO;
    }
}

答案 3 :(得分:6)

根据Core Data Documentation,您不应该继续查看对象是否存在。

  

在许多情况下,您可能需要查找一组离散输入值的现有对象(已存储在商店中的对象)。一个简单的解决方案是创建一个循环,然后为每个值依次执行一个fetch以确定是否存在匹配的持久化对象,依此类推。这种模式不能很好地扩展。如果使用此模式分析应用程序,通常会发现fetch是循环中较昂贵的操作之一(与仅迭代项目集合相比)。更糟糕的是,这种模式将O(n)问题转化为O(n ^ 2)问题。

编辑3月16日
我不是数据库专家,但由于人们要求更有效的解决方案,请考虑这一组:

set1 = [apple, orange, banana, pineapple, lettuce]

我们想知道[mango, apple, grape]是否属于此集合的一部分。

文档告诉我们不要遍历[芒果,苹果,葡萄]并查询数据库依次查找每个项目,因为这很慢。

考虑这个解决方案:

在服务器端散列集:

hash([mango, apple, grape]) = 234095dda321affe...

然后,您可以通过询问服务器是否有任何更改来完全绕过Core Data。 如果集合不同,则可以将对象转储到托管对象上下文中并进行批量保存。

如果您真的想要查看每个对象是否是该集合的一部分,您可以根据索引特征进行提取,例如“带有皮肤的水果”。

答案 4 :(得分:0)

更新为SWIFT 5:

func checkIfItemExist(id: Int, type: String) -> Bool {

    let managedContext = CoreDataStack.sharedInstance.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "DetailsEntity")
    fetchRequest.fetchLimit =  1
    fetchRequest.predicate = NSPredicate(format: "id == %d" ,id)
    fetchRequest.predicate = NSPredicate(format: "type == %@" ,type)

    do {
        let count = try managedContext.count(for: fetchRequest)
        if count > 0 {
            return true
        }else {
            return false
        }
    }catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
        return false
    }
}