我正在开发一个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.
答案 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]];
有一些可能的进一步优化,例如只需获取标识符属性,但根据我的经验,上述内容应解决您的性能问题。