Core-Data executeFetchRequest在后台线程中冻结App

我有一个saveMOC的直接父母的mainMOC ,我需要在线获取另一个tmpMOC为了不阻止我的用户界面,同时从互联网上获取大量的logging。

我的应用程序冻结。 我可以缩小到这一点:

  fetchedItems = [tmpMOC executeFetchRequest:fetchRequest error:&error]; 

我试图把这封装在dispatch_sync[moc.parentcontext.parentcontext.persistentStoreCoordinator lock/unlock][whatevermoc performBlockAndWait]

我也试图取出_mainMOC …没办法…

我明白, executeFetchRequest是不是线程安全的,所以,我怎么locking我需要locking,以确保我没有插入一个双?

任何人都可以帮忙?

更新(1) AppDelegate中的_saveMOC实例:

 - (NSManagedObjectContext *)managedObjectContext { if (_mainMOC != nil) { return _mainMOC; } if (_saveMOC == nil) { NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { _saveMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [_saveMOC setPersistentStoreCoordinator:coordinator]; [_saveMOC setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; } } if (_mainMOC == nil) { _mainMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; [_mainMOC setParentContext:_saveMOC]; [_mainMOC setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; } [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveContextChanges:) name:NSManagedObjectContextDidSaveNotification object:_mainMOC]; 

在MainViewController中创buildtemporaryMOC MOC:

  NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; temporaryContext.parentContext = _mainMOC; [temporaryContext performBlock:^{ //AndWait NSError *error=nil; Feed *feed=(Feed *)[temporaryContext existingObjectWithID:feedID error:&error]; //... [RSSParser parseRSSFeedForRequest:req success:^(NSArray *feedItems) { NSLog(@"[MasterViewController::fetchPosts] inserting %d Posts.../OK", (int)[feedItems count]); feed.valid = [NSNumber numberWithBool:YES]; for(RSSItem *i in feedItems) { [self createPostInFeed:feed withTitle:i.title withContent:(i.content?i.content:i.itemDescription) withURL:[i.link absoluteString] withDate:(i.pubDate?i.pubDate:[NSDate date]) inMOC:temporaryContext]; } [[NSNotificationCenter defaultCenter] postNotificationName:@"NewPostsFetched" object:f]; 

然后冻结发生在createPostInFeed

  // @synchronized(fetchRequest) { // THIS DOESN'T CHANGE ANYTHING // [moc.persistentStoreCoordinator lock]; // THIS NEITHER NSArray *fetchedItems; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *ent = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:moc]; fetchRequest.entity = ent; fetchRequest.propertiesToFetch = [NSArray arrayWithObjects:@"title", @"url", @"feed.name", nil]; [fetchRequest setResultType:NSDictionaryResultType]; fetchRequest.predicate = [NSPredicate predicateWithFormat:@"title == %@ AND url == %@ AND feed.rss == %@", title, url, feed.rss]; NSError *error = nil; fetchedItems = [moc executeFetchRequest:fetchRequest error:&error]; // FREEZES HERE // [moc.persistentStoreCoordinator unlock]; // THIS DOESN'T CHANGE ANYTHING // } // Synchronized neither... 

更新(2):这是时间分析器看到的。 在这里输入图像说明

更新(3):编辑的块:

 NSUInteger fetchedItems; NSString *feedRSS=feed.rss; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *ent = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:moc]; fetchRequest.entity = ent; fetchRequest.predicate = [NSPredicate predicateWithFormat:@"title == %@ AND url == %@ AND feed.rss == %@", title, url, feedRSS]; NSLog(@"MainViewController::createPostInFeed> Before fetchRequest for %@ (%@)", title, url); NSError *error = nil; fetchedItems = [moc countForFetchRequest:fetchRequest error:&error]; NSLog(@"MainViewController::createPostInFeed> After fetchRequest for %@ (%@)", title, url); // THIS NSLOGGING NEVER HAPPENS 

更新(4):调用树倒置的新分析器图片。 在这里输入图像说明

createPostInFeed的目标是什么? 你表明你正在做一个抓取,但是你用这个抓取做什么? 这是一个“插入或更新”检查? 还是只是一个“插入或跳过”testing?

任何提取都将lockingNSPersistentStoreCoordinator并导致您的应用程序在执行提取时可能locking。 有办法来减轻这一点:

  1. 运行仪器
  2. 让你的提取更有效率
  3. 如果你不需要对象(在插入或跳过testing),然后做一个计数
  4. 抓取背景队列,并确保您的主MOC具有所有需要避免locking的对象

你的乐器configuration文件显示给你什么?

createPostInFeed做的是什么取得的结果?