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

don*_*ile 53 iphone core-data objective-c

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

我怎样才能以最有效的方式做到这一点?

Mas*_*aro 96

设置Core Data请求,而不是实际发出查询,请执行以下操作:

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

实际上,该方法countForFetchRequest:error:返回给定的获取请求在传递给它时将返回的对象数executeFetchRequest:error:.


编辑:( 由Regexident提供)

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

if (count == NSNotFound) {
    NSLog(@"Error: %@", error);
    return 0;
}
return count;
Run Code Online (Sandbox Code Playgroud)

或者这个(没有错误记录):

return (count != NSNotFound) ? count : 0;
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此处的错误处理不正确; [在Cocoa中通常就是这种情况](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreomCustomizeNSError.html%23//apple_ref/doc/uid/TP40001806- CH204-SW1),在检查错误对象之前必须检查直接返回值(`count`).在这种情况下,[文档说](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/NSManagedObjectContext.html)返回"NSNotFound"信号错误. (14认同)

sha*_*ikh 25

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

这可以使用

- (NSUInteger)countForFetchRequest:(NSFetchRequest *)request error:(NSError **)error;
Run Code Online (Sandbox Code Playgroud)

像这样的东西:

- (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;

}
Run Code Online (Sandbox Code Playgroud)

  • 是的,但我已经包含了完整的方法和细节. (12认同)
  • 这与接受的答案相同. (2认同)

Dam*_*ito 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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*Jon 6

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

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

编辑3月16日:
我不是数据库专家,但由于人们要求更高效的解决方案,请考虑以下设置:

set1 = [apple, orange, banana, pineapple, lettuce]
Run Code Online (Sandbox Code Playgroud)

我们想知道[mango, apple, grape]是否属于这一组.

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

考虑这个解决方案

在服务器端散列集:

hash([mango, apple, grape]) = 234095dda321affe...
Run Code Online (Sandbox Code Playgroud)

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

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


Jho*_*awk 5

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
    }
}
Run Code Online (Sandbox Code Playgroud)