2013-05-30 53 views
1

我在coredata NSManagedObjectContextDidSaveNotification運行的謂詞來過濾相關的對象我感興趣的。predicateWithFormat很慢

- (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太慢了,佔用了CPU的20%。它甚至不是過濾緩慢。謂詞本身的創建非常緩慢。 如果將其更改爲使用enumerateObjectsUsingBlock,它變得更快,但代碼的可讀性較差。

有沒有人有解釋?謝謝。

回答

1

你不能擊敗你的枚舉使用當前的斷言,有幾個原因過濾實現了時間:

  1. 您分配,解析,並在每次調用構成謂語didSaveNotficiation :
  2. 您使用字符串在你的謂詞中進行比較,其成本要高得多,那麼'isKindOfClass:'class
  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]; 

正如你可以看到,如果試圖以提高可讀性受損。