2013-01-14 39 views
1

我希望這不是一個重複的問題。我似乎無法找到類似的東西。大多數核心數據問題似乎是關於新的對象創建...核心數據多項編輯效率和隨機錯誤

我有一個數據庫大約23,000項目的程序。我正在嘗試創建一個導出/導入功能將數據發送到其他設備(未與iCloud鏈接)。

出口工作得很好,象電子郵件......

我有進口功能,但它慢慢地功能(和,以後會更多,似乎並沒有與iPhone 5以及工作或ipad 3)

我有解析我將數據導入一個NSArray(_importedRows,然後我運行下面的代碼的函數):

self.managedObjectContext = [(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext]; 

    NSManagedObjectContext *ctx = self.managedObjectContext; 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription 
            entityForName:@"CHECKLIST" 
            inManagedObjectContext:ctx]; 
    [fetchRequest setEntity:entity]; 
    ImportedData *importedData; 
    NSString *verify; 
    NSError *error = nil; 
    NSManagedObject *updatedObject; 
    NSArray *matchingItems; 
    for (int i = 0; i < [_importedRows count]; i++) { 
     importedData = [_importedRows objectAtIndex:i]; 
     verify = importedData.uniqueID; 
     [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"uniqueID == %@", verify]]; 
     [fetchRequest setFetchLimit:1]; 
     matchingItems = [ctx executeFetchRequest:fetchRequest error:&error]; 

     for (updatedObject in matchingItems) { 
      HUD.detailsLabelText = [NSString stringWithFormat:@"Updating %@" , [updatedObject valueForKey:@"figureName"]]; 
      [updatedObject setValue:importedData.numberOwned forKey:@"numberOwned"]; 
      [updatedObject setValue:importedData.numberWanted forKey:@"wishList"]; 
      [updatedObject setValue:importedData.availableTrade forKey:@"tradeList"]; 

     } 

     [ctx save:&error]; 

     if (error != nil) { 
      NSLog(@"error saving managed object context: %@", error); 
     } 

    } 

基本上,我抓住一個核心數據實體,然後遍歷我的數組檢查匹配。當我找到一個匹配項(uniqueID謂詞)時,我使用導入的數據更新對象。這段代碼在我的iPhone 4s上正常工作,但速度很慢。 4,000個項目大約需要4-5分鐘。我在做什麼明目張膽的錯誤?我應該更頻繁地調用保存功能嗎?

作爲獎勵,由於某種原因,這個代碼時,我測試它在iPhone 5,9次了10年(的時間和50%的我的iPad 3)幾乎沒有工作,我得到一個

「 1月14日8時06分44秒:*終止應用程序由於未捕獲的異常 'NSInvalidArgumentException',原因是: ' - [__ NSCFSet ADDOBJECT:]:嘗試插入零' 控制檯」

。思考?

讓我知道是否需要更多細節!

UPDATE: 似乎handleOpenURL被調用兩次...一次的applicationDidFinishLaunching NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey]; if (url != nil && [url isFileURL]) { [self.window.rootViewController performSelector:@selector(showWithLabel:) withObject:url afterDelay:6]; }

和曾經在這裏:

-(BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation 

{如果(URL =零& & [URL isFileURL]){ [self.window.rootViewController performSelector:@selector(showWithLabel :) withObject:url]; } return YES; }

我不得不只管鬧這兩個在應用程序的委託,否則該函數並不總是被調用(一次是應用程序啓動時,一旦如果它的應用程序已經在後臺,我相信) - 我已經添加了一個檢查,以防止它在showWithLabel線程中第二次啓動,但它似乎並不是一個非常優雅的解決方案...

UPDATE:@mundi建議清理fetchedresults代碼如下:

NSArray *importedIDs = [_importedRows valueForKeyPath:@"uniqueID"]; 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    fetchRequest.entity = [NSEntityDescription entityForName:@"CHECKLIST" 
             inManagedObjectContext:ctx]; 
    fetchRequest.predicate = [NSPredicate predicateWithFormat: 
           @"uniqueID in %@", importedIDs]; 

    NSError *error = nil; 
    NSManagedObject *updatedObject; 
    NSArray *matchingItems; 
    matchingItems = [ctx executeFetchRequest:fetchRequest error:&error]; 
    ImportedData *importedData; 
    for (int i = 0; i < [_importedRows count]; i++) { 
     importedData = [_importedRows objectAtIndex:i]; 
     for (updatedObject in matchingItems) { 
      if ([importedData.uniqueID isEqualToString:[updatedObject valueForKey:@"uniqueID"]]) { 
       HUD.detailsLabelText = [NSString stringWithFormat:@"Updating %@" , [updatedObject valueForKey:@"figureName"]]; 
       [updatedObject setValue:importedData.numberOwned forKey:@"numberOwned"]; 
       [updatedObject setValue:importedData.numberWanted forKey:@"wishList"]; 
       [updatedObject setValue:importedData.availableTrade forKey:@"tradeList"]; 
      } 


     } 
    } 


    [ctx save:&error]; 

我敢肯定,它仍然是一個小清潔和實際更新部分(我不知道該怎麼辦呢除了將提取結果中的每個項目與初始數組中的每個項目進行比較以確保它們已被正確更新,但組合提取結果極大地提高了速度(最初爲4000個項目的240秒,現在在80-120秒之間)

首先對數組進行排序,然後按順序更新,然後再次加速:

NSArray *matchingItemsSorted; 
    matchingItemsSorted = [matchingItems sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 
     NSString *first = [a valueForKey:@"uniqueID"]; 
     NSString *second = [b valueForKey:@"uniqueID"]; 
     return [first caseInsensitiveCompare:second]; 
    }]; 


    NSArray *importedRowsSorted; 
    importedRowsSorted = [_importedRows sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 
     NSString *first = [a valueForKeyPath:@"uniqueID"]; 
     NSString *second = [b valueForKeyPath:@"uniqueID"]; 
     return [first caseInsensitiveCompare:second]; 
    }]; 

    int i = 0; 
    for (updatedObject in matchingItemsSorted) { 
     NSLog(@"do we match? %@ : %@", [[importedRowsSorted objectAtIndex:i] valueForKeyPath:@"uniqueID"], [updatedObject valueForKey:@"uniqueID"]); 
     HUD.detailsLabelText = [NSString stringWithFormat:@"Updating %@" , [updatedObject valueForKey:@"figureName"]]; 
     [updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:@"numberOwned"] forKey:@"numberOwned"]; 
     [updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:@"numberWanted"] forKey:@"wishList"]; 
     [updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:@"availableTrade"] forKey:@"tradeList"]; 
     i++; 


    } 

對於nslog有4000個項目,13秒左右......現在唯一奇怪的是,當我註釋掉nslog時,它經常崩潰......它發生得太快了,它破壞了核心數據 - 當它沒有崩潰時,它只需要約4秒?

感謝, 扎克

+0

我不確定這是否是您的選擇,但我所做的是在後臺線程上更新我的對象,所以即使需要一分鐘或2分鐘,用戶仍可以使用該應用程序。我不確定是否有任何事情可以更快地進行更新 - 我曾在一個時間點看過它,並且你對我做的最快的方法是什麼。 – RyanG

+0

請看[實現查找或創建高效](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174-SW4)在「核心數據編程指南」中描述了一個很好的模式,它使用一個單一的讀取請求,而不是每個項目的一個讀取請求。同時保存*次數少*,而不是*次數多*。 –

+0

馬丁R - 是的,我現在看到我在循環後保存,所以我會改變,以每100或1000次...我擔心有4,000多個項目的提取請求...也許我不應該是? –

回答

1

你有兩個嵌套循環。使用這種模式來加速:

NSArray *importedIDs = [_importedRows valueForKeyPath:@"uniqueID"]; 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
fetchRequest.entity = [NSEntityDescription entityForName:@"CHECKLIST" 
            inManagedObjectContext:ctx]; 
fetchRequest.predicate = [NSPredicate predicateWithFormat: 
      @"uniqueID in %@", importedIDs]; 

像這樣,你可以獲取一個數組與所有匹配的項目。

+0

有趣。我仍然使用嵌套循環,因爲我需要將數組中的每個項目與每個獲取的項目進行比較以更新正確的值,對嗎?它確實減少了50%的時間! awesome'for(int i = 0; i <[_importedRows count]; i ++){ importedData = [_importedRows objectAtIndex:i]; for(updatedObject in matchedItems){(importedData.uniqueID isEqualToString:[updatedObject valueForKey:@「uniqueID」]]){' –

+0

哇,它從240秒降到我妻子的iPhone 5上的70左右.. 。我將以此作爲答案......雖然第二次嵌套可能實際上不是必需的嗎?思考?我將把完整的代碼放在原始問題中,以便更易於閱讀 –

+0

您絕對必須消除雙重循環。 70秒是可笑的。按uniqueID對數組進行排序,然後一次完成數據複製。 – Mundi