predicateWithFormat 很慢
Posted
技术标签:
【中文标题】predicateWithFormat 很慢【英文标题】:predicateWithFormat is very slow 【发布时间】:2013-05-30 02:34:50 【问题描述】:我在 coredata NSManagedObjectContextDidSaveNotification 中运行一个谓词来过滤我感兴趣的相关对象。
- (void)didSaveNotficiation:(NSNotification*)notification
NSSet *objects = nil;
NSMutableSet *combinedSet = nil;
NSPredicate *predicate = nil;
NSDictionary *userInfo = [notification userInfo];
objects = [userInfo objectForKey:NSInsertedObjectsKey];
combinedSet = [NSMutableSet setWithSet:objects];
objects = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];
[combinedSet unionSet:objects];
objects = [[notification userInfo] objectForKey:NSDeletedObjectsKey];
[combinedSet unionSet:objects];
//THis is slow
predicate = [NSPredicate predicateWithFormat:@"entity.name == %@ && %K == %@",
[XXContact entityName], XXContactRelationship.user,self];
[combinedSet filterUsingPredicate:predicate];
if ([combinedSet count] == 0)
return;
[self process];
/* This is much faster
[combinedSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop)
if ([obj isKindOfClass:[XXContact class]])
XXContact* contact = (XXContact*)obj;
if (contact.user == self)
[self process];
*stop = YES;
];
*/
应用启动时,通知可以被调用超过 100 次。 当我分析应用程序时,函数 predicateWithFormat 似乎太慢了,占用了 20% 的 cpu。甚至不是过滤很慢。谓词本身的创建是如此缓慢。 如果我将其更改为使用 enumerateObjectsUsingBlock,它会变得更快,但代码的可读性会降低。
有人解释一下吗?谢谢。
【问题讨论】:
【参考方案1】:由于以下几个原因,您无法超越使用当前谓词进行枚举过滤所达到的时间:
-
您在每次调用
didSaveNotficiation :
时分配、解析和组合谓词
您在谓词中使用字符串比较,这比 'isKindOfClass:' 类成本高得多
您的实现中有一个停止条件,这在谓词中是不可能的(combinedSet
中的所有对象都必须进行评估)
您的谓词过滤执行正在改变集合(删除对象)
我相信您最好的选择是自己实现谓词
为了改进您的谓词实现,我建议:
//1. change .name property to an Integer/Enum value
//2. make your predicate static and reduce the compose and parse needs:
//(If you must use %K in your predicate this would be much harder)
//NOT TESTED
static NSPredicate* p = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
p = [NSPredicate predicateWithFormat:@"entity.name == $ENAME AND user == $USEROBJECT"];
);
NSPredicate* currPredicate = [p predicateWithSubstitutionVariables:@@"ENAME" : [XXContact entityName], @"USEROBJECT" : [self objectID]];
[combinedSet filterUsingPredicate:currPredicate];
如您所见,如果您尝试提高可读性,则会受到损害。
【讨论】:
以上是关于predicateWithFormat 很慢的主要内容,如果未能解决你的问题,请参考以下文章
yeoman新建webapp时总是很慢,卡在pre-build test上是啥原因
NSPredicate - predicateWithFormat 不安全
用于电子邮件问题的 NSPredicate predicateWithFormat
predicateWithFormat 返回错误的核心数据对象