iOS - 下载大型数据集,检测具有属性值的实体(NSManagedObject)是否已存在

时间:2014-04-20 18:49:13

标签: ios objective-c core-data nsfetchrequest

我正在开发一个iOS应用程序,我从远程Web服务下载大型数据集。我有一个本地核心数据库。我不想保存每个对象的重复项,因此我需要检测具有特定值的对象是否已存在于本地。

我现在这样做的方式有效,但我注意到了一些性能问题。对于每个对象,我当前进行获取请求以查看它是否存在(~500 +次)。我的提取看起来像这样:

+ (Entity *)entityWithIdentifier:(NSString *)identifier {

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];

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

    fetchRequest.predicate = predicate;

    [fetchRequest setFetchLimit:1];

    NSError *error;

    NSArray *array = [[AppDelegate sharedDelegate] backgroundContext] executeFetchRequest:fetchRequest error:&error];

    return array.firstObject;
}

如前所述,这个方法经常被调用 - 对于我想要解析的每个远程对象(创建/插入或更新)。

它目前阻止主线程约2000ms,并且随着数据集的增长会更糟。什么是最有效的方式来做我想要的:

1. Check if object with value exists locally. 
2. If it exists, return it, if not return nil and create a new local object.

1 个答案:

答案 0 :(得分:1)

我的建议是用一次抓取来替换500多次抓取。首先使用KVC在单个阵列中提取所有下载的ID。

NSArray *downloadedIDs = [downloadedRecords valueForKeyPath:@"identifier"];

然后使用此谓词进行单次提取:

[NSPredicate predicateWithFormat:@"identifier in %@", downloadedIDs];

现在,您可以遍历剩余的ID以创建新对象。一旦提取现有的ID,获得剩余的IDS也非常简单:

NSArray *existingIDs = [fetchedObjects valueForKeyPath:@"identifier"];
NSArray *remainingIDs = [downloadedIDs filteredArrayUsingPredicate:
 [NSPredicate predicateWithFormat:@"self not in %@", existingIDs]];

有一些可能的进一步优化,例如只需获取标识符属性,但根据我的经验,上述内容应解决您的性能问题。