1

我目前正在开发一个使用CoreData和NSFectchedResultsController的应用程序。此应用程序只包含一个使用NSFetchedResultsController的UITableView。NSFetchedResultsController/CoreData与多个线程问题

1/当应用程序启动时,另一个线程被分离。在这个新线程中,WS调用允许从Web服务器检索数据。在WS调用之后,我用另一个NSManagedObjectContext(Apple的最佳实践:另一个线程=>另一个上下文)将数据存储在我的CoreData DB中。在保存新对象之前,我必须删除此实体的所有对象。我通过mergeChangesFromContextDidSaveNotification将其他上下文与主要上下文合并。

 // Data Manager (in another thread) 
     NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; 
     [[NSNotificationCenter defaultCenter] addObserver:self 
               selector:@selector(contextDidSave:) 
               name:NSManagedObjectContextDidSaveNotification 
               object:context]; 
     [context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; 
     [context setPersistentStoreCoordinator:[self getPersistentStoreCoordinator]]; 

     ... 

     for (NSManagedObject * obj in objects) 
     { 
      [context deleteObject:obj]; 
     } 

     ... 

     for(NSDictionary *serverObj in serverObjects) 
     { 
      objAd = [NSEntityDescription 
         insertNewObjectForEntityForName:@"MyEntity" 
         inManagedObjectContext:context]; 
      ... 
     } 

     [context save:&error]; 

     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:context]; 
     [context release]; 

     ... 

     - (void)contextDidSave:(NSNotification *)notification 
     { 

      SEL selector = @selector(mergeChangesFromContextDidSaveNotification:); 
      [[self getContext] performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES]; 
     } 

     - (NSManagedObjectContext *) getContext 
     { 
      return [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
     } 

     - (NSPersistentStoreCoordinator *) getPersistentStoreCoordinator 
     { 
      return [(AppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator]; 
     } 

2/这里是我的NSFectchedResultsController的getter:

 // UIView 
    - (NSFetchedResultsController*) offersFRC { 

     if (offersFRC == nil) 
     { 
      NSManagedObjectContext *l_ManagedObjectContext = [[DataManager sharedDataManager] getContext]; 

      NSFetchRequest *l_FetchRequest = [[NSFetchRequest alloc] init]; 

      NSEntityDescription *l_Entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:l_ManagedObjectContext]; 
      [l_FetchRequest setEntity:l_Entity]; 

      [l_FetchRequest setFetchBatchSize:5]; 

      NSNumber *sortType = [self.searchCriterions objectForKey:@"sortType"]; 
      NSSortDescriptor *l_SortDescriptor = [[NSSortDescriptor alloc] initWithKey:[Constants getFieldNameBySortType:sortType] ascending:[Constants isAscendingBySortType:sortType]]; 
      [l_FetchRequest setSortDescriptors:[NSArray arrayWithObjects:l_SortDescriptor, nil]]; 
      [l_SortDescriptor release]; 

      NSFetchedResultsController *l_FetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:l_FetchRequest                          managedObjectContext:l_ManagedObjectContext 
       sectionNameKeyPath:nil                          
       cacheName:nil]; 
      [l_FetchRequest release]; 

      [self setOffersFRC:l_FetchedResultsController]; 
      [l_FetchedResultsController release],l_FetchedResultsController = nil; 

      [self.offersFRC setDelegate:self]; 
     } 

     return offersFRC; 
    } 

3/当应用程序启动,我得到了以下错误:

 2012-02-29 11:56:09.119 Nanopost[1996:207] *** Terminating app due to uncaught exception  'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x5c3c760 <x-coredata://E176B0A1-275B-4332-9231-49FD88238C2B/Ads/p231>'' 
    *** Call stack at first throw: 
    (
    0 CoreFoundation      0x02bfe919 __exceptionPreprocess + 185 
    1 libobjc.A.dylib      0x02e595de objc_exception_throw + 47 
    2 CoreData       0x028b833f _PFFaultHandlerLookupRow + 1407 
    3 CoreData       0x028b5ee3 _PF_FulfillDeferredFault + 499 
    4 CoreData       0x028b9f3f _sharedIMPL_pvfk_core + 95 
    5 CoreData       0x0292a010 _PF_Handler_Public_GetProperty + 160 
    6 Foundation       0x02442c4f -[NSSortDescriptor compareObject:toObject:] + 128 
    7 CoreData       0x0297db5e +[NSFetchedResultsController(PrivateMethods) _insertIndexForObject:inArray:lowIdx:highIdx:sortDescriptors:] + 286 
    8 CoreData       0x0297e1b2 -[NSFetchedResultsController(PrivateMethods) _postprocessInsertedObjects:] + 402 
    9 CoreData       0x029841bc -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 1804 
    10 Foundation       0x02380c1d _nsnote_callback + 145 
    11 CoreFoundation      0x02bd6cf9 __CFXNotificationPost_old + 745 
    12 CoreFoundation      0x02b5611a _CFXNotificationPostNotification + 186 
    13 Foundation       0x023767c2 -[NSNotificationCenter postNotificationName:object:userInfo:] + 134 
    14 CoreData       0x028c0519 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 89 
    15 CoreData       0x028f802b -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] + 1579 
    16 Foundation       0x02395e9a __NSThreadPerformPerform + 251 
    17 CoreFoundation      0x02bdfd7f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 
    18 CoreFoundation      0x02b3e2cb __CFRunLoopDoSources0 + 571 
    19 CoreFoundation      0x02b3d7c6 __CFRunLoopRun + 470 
    20 CoreFoundation      0x02b3d280 CFRunLoopRunSpecific + 208 
    21 CoreFoundation      0x02b3d1a1 CFRunLoopRunInMode + 97 
    22 GraphicsServices     0x031e62c8 GSEventRunModal + 217 
    23 GraphicsServices     0x031e638d GSEventRun + 115 
    24 UIKit        0x0063cb58 UIApplicationMain + 1160 
    25 Nanopost       0x0000230a main + 170 
    26 Nanopost       0x00002255 start + 53 
    ) 
    terminate called after throwing an instance of '_NSCoreDataException' 

重要笔记

  • 它崩溃只在iOS4的
  • controllerWillChangeContent是之前的应用程序的崩溃叫我的代码中的最后一个函数。不调用controllerDidChangeContent/didChangeObject/didChangeSection。
  • 当我评论[l_FetchRequest setFetchBatchSize:5] =>没有更多的崩溃
  • 当我添加[上下文保存:&错误]之后的对象的删除和之前新对象插入=>没有更多的崩溃
  • 当我使用[l_FetchRequest setFetchBatchSize:24] =>崩溃
  • 当我使用[l_FetchRequest setFetchBatchSize:25] =>没有更多的崩溃

我已经花了很多的时间去理解这个问题,所以谢谢你非常提前为您的答案!

托马斯

编辑1(@Jody): 喜乔迪和非常感谢你对你的答案!

下面是用于处理contextDidSave代码:

- (void)contextDidSave:(NSNotification *)notification 
    { 
     SEL selector = @selector(mergeChangesFromContextDidSaveNotification:); 
     [[self getContext] performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES]; 
    } 

“你得先告诉我更多关于你正在使用的情境”:

我用2个上下文在这个应用程序:

  • 编号1:创建XCodeProject时默认在AppDelegate中创建。这个上下文被我的FRC使用,并允许显示UITableView的行。N°2:在我的“DataManager”(我的文章中的第一个代码块)中创建,一个允许刷新我的DB(WS调用,删除,重新插入,保存)的单例。

当上下文N°2被保存,contextDidSave被称为合并这方面与主上下文(上下文N°1)。之后,我的FRC委托人的方法“controllerWillChangeContent”被调用。我认为它不会帮助显示包含在这个方法中的代码,因为即使我只是放了一个NSLog,它在这个方法之后崩溃了(我放了很多NSLog,并且controllerWillChangeContent中包含的NSLog是之前显示的最后一个碰撞)。

我已经贴在苹果开发论坛,并有一个有趣的答案:https://devforums.apple.com/thread/152172?tstart=0

编辑2(@Jody): 嗨乔迪!

正如你可以在下面的方法看,我的FRC不从其他线程使用MOC:

- (NSManagedObjectContext *) getContext 
    { 
     return [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
    } 

我“的DataManager”的这个方法返回的AppDelegate的MOC(=主线程MOC)

回答

0

您正在从一个上下文的数据库中删除,因此您必须适当地刷新其他上下文,并且特别是摆脱删除数据的对象引用。

什么是你的处理contextDidSave的代码:?此外,您的FRC委托人如何处理数据更新通知?

编辑

它看起来像你混淆你的管理对象上下文。您正在使用一个在数据管理器来加载和修改数据库...

// Data Manager (in another thread) 
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; 

,然后使用“默认”建设部的数据拉入你的应用程序通过通知,但它看起来像你获取的成果控制器还试图使用MOC从另一个线程...

NSManagedObjectContext *l_ManagedObjectContext = [[DataManager sharedDataManager] getContext]; 

它或许应该使用的主要MOC(从应用程序委托)为好。

+0

你不应该把代码放在注释中,因为它没有格式。另外,编辑问题以提供更好的问题是要走的路。至于代码,在我解决DidSave处理问题之前,您首先必须告诉我更多关于您正在使用的上下文......再次,它是从哪里来的?它是如何创建的?它与MR环境有什么关系? –

+0

糟糕。同样的问题,但是无视MR部分(在路上回答(在Hardees),并且把它和另一个问题混合在一起,对不起有任何困惑 –

+0

谢谢Jody!我编辑了我的问题! –