2012-09-26 57 views
1

我的核心數據存儲包含51 Entry實體,它們的message屬性讀取「測試」。爲此做NSFetchRequest證實他們都在那裏。NSManagedObjectContext重置似乎丟失數據?

但是我有另一部分我的方法,它將用於內存密集型目的,處理大塊的NSData,所以我需要經常撥打[oldContext reset];

我有一個內存密集型方法,它從我的MOC中訪問大量的NSData。因此,它定期致電[oldContext reset];。沒有這條線,它將耗盡內存。

我發現通過使用它雖然它沒有返回正確的結果。爲了測試這一點,我註釋了數據密集型代碼,留下的代碼返回了message屬性,其中51個屬性設置爲「Test」(由單獨的NSFetchRequest確認)。

使用[oldContext reset];但是,它只返回6個結果,消息設置爲「測試」。這是我正在使用的代碼:

NSFetchRequest *oldFetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *oldEntryEntity = [NSEntityDescription entityForName:@"Entry" 
                 inManagedObjectContext:oldContext]; 
    [oldFetchRequest setEntity:oldEntryEntity]; 
    [oldFetchRequest setFetchBatchSize:10]; 
    [oldFetchRequest setIncludesPropertyValues:NO]; 
    NSArray *entrys = [oldContext executeFetchRequest:oldFetchRequest error:&error]; 

    int totalEntries = [oldContext countForFetchRequest:oldFetchRequest error:nil]; 

    int i = 0; 

    while (i < totalEntries) { 
     @autoreleasepool { 

      Entry *entry = [entrys objectAtIndex:i]; 

      NSLog(@"message 1: %@", [entry valueForKey:@"message"]); 


      [oldContext reset]; 


      i++; 
     } 
    } 

任何想法爲什麼它沒有給出51「測試」結果它應該這樣做?

回答

1

嘗試設置獲取批量大小爲1,而不是目前的10

我這種情況的解釋如下。

  1. 通過executeFetchRequest...它將10條記錄提取到上下文中。
  2. 但是,通過重置上下文,所有記錄都將丟失。所以,只有10條記錄中的第一條記錄。請注意,在上下文重置之前記錄第一條記錄。
  3. 由於我們共有51條記錄,因此我們保留51 % 10 = 6條記錄。
+0

好吧,這解決了我的問題,但它使我的應用程序回到崩潰 - 這樣做的內存使用量增加了10倍。 – Andrew

+0

這是簡化的示例應用程序崩潰嗎?或者你有一些額外的原始應用程序? – barley

+0

原文。兩者的內存使用量都增加了10倍。 – Andrew

1
NSFetchRequest *oldFetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *oldEntryEntity = 
    [NSEntityDescription entityForName:@"Entry" 
       inManagedObjectContext:oldContext]; 
[oldFetchRequest setEntity:oldEntryEntity]; 
[oldFetchRequest setFetchBatchSize:10]; 
[oldFetchRequest setIncludesPropertyValues:NO]; 
NSArray *entrys = [oldContext executeFetchRequest:oldFetchRequest error:&error]; 
int totalEntries = [oldContext countForFetchRequest:oldFetchRequest error:nil]; 

上面的代碼執行對MOC oldContext一個取指令請求。因此,entrys數組將包含數據庫中與請求匹配的每個對象的託管對象。另外,由於設置了批處理大小,抓取會錯誤處理對象的批處理大小。

作爲一個實驗,以確保自己發生了什麼,添加這些日誌語句...

NSLog(@"entrys count = %u", entrys.count); 
for (NSManagedObject *entry in entrys) { 
    NSLog(@"entry: %@", entry); 
} 

你看到的是該數組中?現在有意義嗎?

讓我們來看看其餘的代碼。

int i = 0; 
while (i < totalEntries) { 
    @autoreleasepool { 
     // You get the i-th entry. It will be a managed object. It could be a fault 
     // or it could be a fully hydrated object. Based on your batch size, the 
     // first ten (0 <= i < 10) will be complete objects. 
     Entry *entry = [entrys objectAtIndex:i]; 

     // Log the "message" attribute. By calling valueForKey, the object will be 
     // faulted into memory if it is a fault. Since your batch size is 10, 
     // this will make sure 10 objects are faulted if one is needed. 
     NSLog(@"message 1: %@", [entry valueForKey:@"message"]); 

     // Resetting the entire context blows away everything in the context. 
     // Calling reset is a hard call, and should not be done if you have 
     // references to the objects in the context. 
     [oldContext reset]; 

     i++; 
    } 
} 

我會建議一種不同的方法。調用reset不適用於您將保留對象的上下文。

有幾種選擇。你可以創建一個子上下文,在那裏做你的臨時工,然後釋放上下文。它將釋放它使用的所有內存。

你可以選擇使用

- (void)refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag 

這會變成一個對象返回到一個故障,如果flagNO,釋放它的內存。請注意,這也有一些固有的危險,特別是如果你有管理關係。

還有其他一些選擇,但是不知道你的最終目標是什麼......有點難以分辨哪些是最有利的。

我強烈建議您閱讀與這些調用相關的所有文檔。事實上,雖然核心數據非常複雜,但它確實有一些「脆弱」的互操作性,如果你做任何不重要的事情,你都應該知道這些。

我強烈建議閱讀所有核心數據文檔。它解決了您在項目中遇到的所有問題。

1

按照蘋果的文檔,這就是ManagedObjectContext復位作用:「遺忘」

  • 所有接收方的管理對象是如果你使用這種方法,你應該確保你也拋棄引用到使用接收器獲取的任何託管對象,因爲之後它們將無效。

因此,在你的代碼,你告訴oldContext每一次它的所有對象的忘記,而循環迭代。

你不是說那裏的MOC是NSData的是從哪裏來的,但如果從進入實體的,我說你有兩個選擇:

1)相反,每次重置商務部,使用NSManagedObjectContext的refreshObject:mergeChanges:方法。這將重新排除實體並釋放內存。例如:

while (i < totalEntries) { 
    @autoreleasepool { 

     Entry *entry = [entrys objectAtIndex:i]; 

     NSLog(@"message 1: %@", [entry valueForKey:@"message"]); 


     [oldContext refreshObject:entry mergeChanges:NO]; 


     i++; 
    } 
} 

2)不要在Core Data實體中存儲大量數據。相反,將數據寫入文件系統並保留對實體中數據路徑的引用。這將是我的首選方法。看看蘋果的Core Data Performance下的「大數據對象」部分

+0

由於我不明白的原因,號碼1不起作用。它沒有釋放任何內存,並在通常的同一點崩潰。至於數字2,這是處理來自應用商店中已有應用的數據,所以這不是一種選擇。 – Andrew

+0

你是否在Entry對象中存儲NSData?如果在while循環中註釋掉NSLog行會發生什麼?數據出現故障並且不能再次退出。 – ChrisH

相關問題