2011-02-08 96 views
1

我想導入一個大型數據集(~6,000)到我的核心數據應用程序。我讀過Apple文檔「Efficiently Importing Data」,我想我正確設置了它。奇怪的是,應用程序在模擬器中沒有崩潰,但是如果我使用Leaks工具運行應用程序,但它不會保存所有數據。有時它只會節省3-4百次,這將節省3-4千次,而且很少會整個數據集。我認爲這可能是內存泄漏相關,我很新的使用NSAutoReleasePool,任何幫助將不勝感激。核心數據導入失敗

NSURL *url = [NSURL URLWithString:@""]; 

    NSString *responseString = [NSString stringWithContentsOfURL:url encoding:NSASCIIStringEncoding error:nil]; 

    if (responseString) { 
     NSArray *players = [responseString componentsSeparatedByString:@";"]; 

     NSUInteger LOOP_LIMIT = 100, count = 0; 

     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

     NSManagedObjectContext *context = [[AppController sharedAppController] managedObjectContext]; 
     [context setUndoManager:nil]; 

     for (int i=0; i<([players count] - 1); i++) { 
      NSArray *info = [[players objectAtIndex:i] componentsSeparatedByString:@","]; 

      NSString *dateInfo = [info objectAtIndex:10]; 
      NSLocale *usLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease]; 
      NSDateFormatter *fo = [[[NSDateFormatter alloc] init] autorelease]; 
      [fo setDateFormat:@"MM/dd/yyyy"]; 
      [fo setLocale:usLocale]; 
      [fo setTimeZone:[NSTimeZone systemTimeZone]]; 
      NSDate *dob = [fo dateFromString:dateInfo]; 

      Players *player = [NSEntityDescription insertNewObjectForEntityForName:@"Players" 
                  inManagedObjectContext:context]; 

      NSNumberFormatter *f = [[[NSNumberFormatter alloc] init] autorelease]; 
      [f setNumberStyle:NSNumberFormatterNoStyle]; 

      player.playerID = [f numberFromString:[info objectAtIndex:0]];    
      player.lastName = [info objectAtIndex:1]; 
      player.firstName = [info objectAtIndex:2]; 
      player.position = [info objectAtIndex:4]; 

      NSString *teamName = [info objectAtIndex:3]; 

      NSFetchRequest *req = [[[NSFetchRequest alloc] init] autorelease]; 

      NSEntityDescription *ent = [NSEntityDescription entityForName:@"Teams" inManagedObjectContext:context]; 
      [req setEntity:ent]; 
      [req setIncludesPropertyValues:NO]; 

      NSPredicate *pre = [NSPredicate predicateWithFormat:@"team=%@", teamName]; 
      [req setPredicate:pre]; 

      NSArray *list = [context executeFetchRequest:req error:nil]; 

      if ([list count]) { 
       Teams *team = [list objectAtIndex:0]; 

       player.team_Players_Teams = team; 
      } 

      count++; 

      if (count == LOOP_LIMIT) { 
       [context save:nil]; 

       [context reset]; 

       [pool drain]; 

       pool = [[NSAutoreleasePool alloc] init]; 

       count = 0; 
      } 
     } 

     if (count != 0) { 
      NSLog(@"In Save Remaining"); 

      [context save:nil]; 

      [context reset];[pool drain]; 
     } 
+1

[池漏]末尾缺失 – Felix 2011-02-08 17:59:14

+0

正確 - 我剛剛添加,但不應該影響實際導入。導入過程中仍然存在一些錯誤。 – nlutterman 2011-02-08 18:15:53

回答

0

我在代碼中看不到任何狡猾的東西。絕對不會出現在日誌中的錯誤?

另外一個在覈心數據pdf中介紹的用於導入數據的其他優化技巧是將謂詞創建移到循環外並使用替換變量。

0

我看不到任何明顯的滲漏,但:

  1. 你可以儘量減少內存alloc init retain -ing使用量的NSLocaleNSDateFormatterNSNumberFormatter然後release後的-ing他們循環完成。這些在循環的運行之間似乎沒有改變。

  2. 我不知道Core Data,但是NSManagedObject/Player *player對象在哪裏發佈?這是通過核心數據自動發佈的嗎?

  3. 順便說一句,你可以使用[list lastObject]而不是[list count][list objectAtIndex:0]作爲最後的兩人將崩潰,如果名單是零

更新基於響應:

如果沒有出現做出那麼下一步就是簡化代碼以刪除任何錯誤來源。

  1. 在上面#1中執行我的建議,以儘量減少循環中的代碼量。

  2. 檢查您是否在某處釋放了list對象,或者它是否被分配爲autorelease。

  3. 刪除中間保存(count == LOOP_LIMIT中的所有代碼),只有在處理完所有陣列後才保存並清空池。您也不應該需要以下代碼if (count != 0)

  4. 用適當的error:&&error和日誌錯誤替換語句。要記錄這些錯誤執行下列操作(道歉,但代碼的格式似乎不工作 - 不知道爲什麼): NSError *error = nil; //Declared upfront

    // Your streamlined code

    // ....

    error = nil; //Just before a fetchRequest or context:save

    /* After looping through all your code now attempt to save */

    if(![context save:&error]) {

    NSLog(@"Failed to save to data store: %@", [error localizedDescription]); 
    NSArray *detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey]; 
    if(detailedErrors != nil && [detailedErrors count] > 0) { 
        for(NSError *detailedError in detailedErrors) { 
         NSLog(@"DetailedError: %@", [detailedError userInfo]); 
        } 
    } else { 
        NSLog(@" %@", [error userInfo]); 
    } 
    

    }

  5. 然後檢查日誌,看看你得到任何奇怪的消息。您也可以在覈心數據中的任何位置使用類似的代碼來檢查錯誤(即executeFetchRequest)。值得一試,找出錯誤在這裏。

+0

NSManagedObject播放器應該與我相信的池一起發佈。不幸的是它仍然崩潰,我不知道爲什麼。 – nlutterman 2011-02-09 21:08:37