2016-04-07 40 views
1

我得到一個不可重現的崩潰,我不知道爲什麼。我在後臺隊列上緩存圖像。圖像名稱是Core Data NSManagedObject子類CCCard上的屬性。與此同時,我有一個訪問這些CCCards的集合視圖。iOS核心數據dispatch_async後臺排隊崩潰

下面是相關的代碼和注意事項。

//CCDeckViewController.m -------------------------------------- 

- (void)viewDidLoad { 
    // This will fetch the CCCard objects from Core Data. 
    self.cards = [[CCDataManager shared] cards]; 

    [self cacheImages]; 
} 

- (void)cacheCardImages { 
    // Because these are NSManagedObjects, I access them in the background 
    // via their object ID. So pull the IDs out here. 
    NSArray *cardIds = [self.cards valueForKey:@"objectID"]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ 
     for (NSManagedObjectID *cardId in cardIds) { 

      // Fetch the actual CCCard object. 
      CCCard *card = (CCCard *)[[CCDataManager shared] objectWithId:cardId]; 

      // Cache the card's image if it's not already there. 
      NSString *key = [card thumbnailCacheKey]; 
      if ([self.cardImageCache objectForKey:key]) { 
       continue; 
      } 
      CCDiscardableImage *discardable = [CCHelper decompressedImageForPath:key size:[card thumbnailSize] tintable:[card tintable]]; 
      [self.cardImageCache setObject:discardable forKey:key]; 
     } 
    }); 
} 

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 
    CCCard *card = self.cards[indexPath.item]; 

    // This line calls the code that crashes. 
    UIColor *color = [card color]; 

    // More code that returns the cell. 
} 


// CCCard.m -------------------------------------- 

- (UIColor *)color { 
    // Crash happens on this line. 
    if (self.colorId.integerValue == 0) { 
     // some code 
    } 
} 

下面是從Crashlytics報告,我認爲堆棧跟蹤的部分最相關:

Thread #0: Crashed: com.apple.main-thread 
EXC_BREAKPOINT 0x000000000000defe 
0 CoreData      0x24c1b070 _sharedIMPL_pvfk_core + 247 
1 CoreData      0x24c1b071 _sharedIMPL_pvfk_core + 248 
2 myapp       0x4286f -[CCCard color] (CCCard.m:37) 
3 myapp       0x40bbb -[CCDeckViewController collectionView:cellForItemAtIndexPath:] (CCDeckViewController.m:127) 

Thread #4: com.apple.root.utility-qos 
0 libsystem_pthread.dylib  0x2321920c RWLOCK_GETSEQ_ADDR 
1 libsystem_pthread.dylib  0x23219295 pthread_rwlock_unlock + 60 
2 libobjc.A.dylib    0x22cb8e01 rwlock_tt<false>::unlockRead() + 8 
3 libobjc.A.dylib    0x22cb5af5 lookUpImpOrForward + 488 
4 libobjc.A.dylib    0x22cb5903 _class_lookupMethodAndLoadCache3 + 34 
5 libobjc.A.dylib    0x22cbbd7b _objc_msgSend_uncached + 26 
6 CoreData      0x24c1d3ab _PFObjectIDFastEquals64 + 38 
7 CoreFoundation     0x233eeed4 CFBasicHashFindBucket + 1820 
8 CoreFoundation     0x233ee775 CFDictionaryGetValue + 116 
9 CoreData      0x24c17037 _PFCMT_GetValue + 122 
10 CoreData      0x24c16ec7 -[NSManagedObjectContext(_NSInternalAdditions) _retainedObjectWithID:optionalHandler:withInlineStorage:] + 58 
11 CoreData      0x24c1b45d _PF_FulfillDeferredFault + 940 
12 CoreData      0x24c1afcf _sharedIMPL_pvfk_core + 86 
13 myapp       0x42991 -[CCCard imagePath] (CCCard.m:53) 
14 myapp       0x41d5b __39-[CCDeckViewController cacheCardImages]_block_invoke (CCDeckViewController.m:295) 

這是令人沮喪,因爲它的發展過程中從未發生過,所以無法測試任何理論。我正在嘗試瞭解代碼和崩潰報告以現在找出問題。我的猜測是它與錯誤有關,因爲它訪問CCCard對象的實例方法,但是當試圖從它讀取屬性時會崩潰。但爲什麼?

+1

colorId屬性的類型是什麼?它在模型中是什麼類型的? – dudeman

+0

'colorId'是'NSNumber'類型(它必須自NSManagedObject之後)。 – guptron

回答

4

您違反了線程限制。

根據核心數據文檔,與其關聯的NSManagedObjectContext和任何NSManagedObject只能在分配給它的隊列上訪問。

您的dispatch_async違反該規則,需要更正。不再有像這樣在dispatch_async中使用核心數據的設計。

如果你想處理是異步的,那麼你應該產生一個私人的NSManagedObjectContext這是你的主要NSManagedObjectContext的孩子,然後執行一個-performBlock:反對它。這會給你正確配置的後臺處理。

此外,我強烈建議打開-com.apple.CoreData.ConcurrencyDebug 1,因爲這會在開發過程中發現類似問題。

+0

感謝Marcus的回答。有什麼辦法可以確定它確實是導致崩潰的線程約束違規嗎?我在單個數據存儲中擁有大約5個表,並且當我們試圖保存一個特定表的更改時總會發生崩潰。我知道我的應用程序中存在很多併發違規,但我無法「證明」這些違規行爲正在導致崩潰,以便我推動修復。會真的很感激你的想法?順便說一下,期待您的新書 – shrutim

+1

正如我在最後一句中所說的:打開貨幣調試標誌:'-com.apple.CoreData.ConcurrencyDebug 1',如果您有線程問題,您將知道**某些** 。 –

+0

謝謝..我這樣做了,我知道我有線程問題..假設我有線程問題,下面的語句是正確的嗎? 「ManagedObjectContext.save()中發生的隨機崩潰是由於線程問題造成的」 – shrutim