2016-04-07 41 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