objective-c 检查核心数据中是否存在对象的最快方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2252109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:55:45  来源:igfitidea点击:

Fastest way to check if an object exists in Core Data or not?

objective-ciphonecore-data

提问by dontWatchMyProfile

I want to see if an object is persisted in Core Data or not. For example, I have Friends in Core Data, and I identify them by firstName. I can query core data to see if "George" is known. If the result set array contains more than zero objects, I know George is there. But Core Data loads the whole thing into memory, and I actually just want to know if George is stored or not.

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

How would I do it the most efficient way?

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

回答by Massimo Cafaro

Setup a Core Data request and, instead of actually issuing the query, do the following:

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

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

In practice, the method countForFetchRequest:error:returns the number of objects a given fetch request would have returned if it had been passed to executeFetchRequest:error:.

在实践中,该方法countForFetchRequest:error:返回给定获取请求如果已传递给 将返回的对象数executeFetchRequest:error:



Edit:(by Regexident)

编辑:(由Regexident)

As Josh Caswellcorrectly commented, the correct way to handle errors is either this:

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

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

or this (without error logging):

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

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

回答by shaikh

Yes, definitely there is a better method. Setup a fetch request as usual, but, instead of actually executing it, simply ask for the number of objects it would have returned if it had been passed to executeFetchRequest:error:

是的,肯定有更好的方法。像往常一样设置一个获取请求,但是,而不是实际执行它,只需询问如果它已传递给 executeFetchRequest:error 它将返回的对象数量:

This can be done using

这可以使用

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

Something like this:

像这样的东西:

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

}

回答by Damien Romito

If the goal is to check if the object exist the solution is to implement this method in your Friend Model:

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

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

回答by Jon

According to Core Data Documentation, you should not keep fetching to see if objects exists.

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

There are many situations where you may need to find existing objects (objects already saved in a store) for a set of discrete input values. A simple solution is to create a loop, then for each value in turn execute a fetch to determine whether there is a matching persisted object and so on. This pattern does not scale well. If you profile your application with this pattern, you typically find the fetch to be one of the more expensive operations in the loop (compared to just iterating over a collection of items). Even worse, this pattern turns an O(n) problem into an O(n^2) problem.

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

Edit March 16:
I am not a db expert, but since people are asking for a more efficient solution, consider this set:

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

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

We want to find out if [mango, apple, grape]is a part of this set.

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

The docs tell us not to iterate through [mango, apple, grape] and query the database looking for each item in turn because this is slow.

文档告诉我们不要遍历 [mango、apple、grave] 并查询数据库依次查找每个项目,因为这很慢。

Consider this solution:

考虑这个解决方案:

Hash the sets on the server side:

在服务器端散列集合:

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

You can then bypass Core Data completely by asking the server if anything changed. If the sets are different, you can then dump the objects in a managed object context and do a bulk save.

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

If you were really looking to see if each object in turn was a part of the set, you could do a fetch based on an indexed characteristic, such as "fruit with skin".

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

回答by JhonnyTawk

Update to SWIFT 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
    }
}