1

我在 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;
                    }
                }
            }];
*/
}

The notification can be called over 100 times when the app starts. When I profile the app, it seems that the function predicateWithFormat is so slow that is taking up 20% of cpu. It is not even the filtering that is slow. The creation of the predicate itself is so slow. If I change it to use enumerateObjectsUsingBlock, it becomes much faster, but the code is less readable.

Does anyone has a explanation? Thanks.

4

1 回答 1

1

由于以下几个原因,您无法超过使用当前谓词进行枚举过滤所达到的时间:

  1. 您在每次调用时分配、解析和组合谓词didSaveNotficiation :
  2. 您在谓词中使用字符串比较,这比 'isKindOfClass:' 类成本高得多
  3. 您的实现中有一个停止条件,这在谓词中是不可能的(combinedSet必须评估其中的所有对象)
  4. 您的谓词过滤执行正在改变集合(删除对象)

我相信您最好的选择是自己实施谓词

为了改进您的谓词实现,我建议:

//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];

如您所见,如果您试图提高可读性,则会受到损害。

于 2013-05-30T05:33:40.003 回答