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

时间:2014-05-06 21:34:16

标签: ios multithreading core-data nsmanagedobjectcontext nsfetchrequest

我有一个saveMOC,它是mainMOC的直接父级,我需要在线获取另一个tmpMOC,以便在从大量记录中获取大量记录时阻止我的用户界面互联网。

我的应用冻结了。 我可以将它缩小到这一点:

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

我尝试将其括在dispatch_sync[moc.parentcontext.parentcontext.persistentStoreCoordinator lock/unlock][whatevermoc performBlockAndWait] ...

我也尝试获取_mainMOC ......没办法......

我理解executeFetchRequest不是线程安全的,所以,我如何锁定我需要锁定的东西以确保我没有插入双?

有人可以帮忙吗?

更新(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中创建

temporaryMOC

    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): 这是Time Profiler看到的内容。 enter image description here

更新(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): 与呼叫树倒置的新的探查器pic。 enter image description here

1 个答案:

答案 0 :(得分:3)

createPostInFeed的目标是什么?你表明你正在进行一次获取,但你对该获取做了什么?这是“插入或更新”检查吗?或者它只是一个“插入或跳过”测试?

任何提取都会锁定NSPersistentStoreCoordinator并导致应用程序在执行提取时可能锁定。有办法缓解这个问题:

  1. 运行乐器
  2. 提高您的提取效率
  3. 如果您不需要对象(在插入或跳过测试中),则执行计数
  4. 获取后台队列并确保主MOC具有避免锁定所需的所有对象
  5. 您的乐器资料会显示给您什么?

    createPostInFeed对该抓取的结果做了什么?