多线程核心数据导致UI挂起

时间:2014-01-23 11:10:19

标签: ios multithreading core-data

我正在尝试在我的应用程序的后台对相当大的数据集(~60000行)执行提取。尽管使用了一个单独的线程,但每当执行获取时,UI都会显着挂起一秒钟。我的方法是否正确?

- (id)init
{
    if(self = [super init])
    {
        ABAppDelegate *appDelegate = (ABAppDelegate *)[[UIApplication sharedApplication] delegate];
        _rootManagedObjectContext = appDelegate.managedObjectContext;

        _backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_backgroundContext setPersistentStoreCoordinator:_rootManagedObjectContext.persistentStoreCoordinator];
    }
    return self;
}


- (void)fetch {
    [_backgroundContext performBlock:^{
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"ItemPhoto"];
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"full_uploaded_to_server == 0 OR thumb_uploaded_to_server == 0"];
        fetchRequest.predicate = pred;
        NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"modified" ascending:YES]; //Start at the back of the queue
        fetchRequest.sortDescriptors = [NSArray arrayWithObject:sort];
        fetchRequest.fetchBatchSize = 1;
        fetchRequest.fetchLimit = 1;

        NSError *error;
        NSArray *photos = [_backgroundContext executeFetchRequest:fetchRequest error:&error];
        if(error != nil) {
            NSLog(@"Fetch error: %@", error.localizedDescription);
        }
    }];
}

查看乐器,这肯定是对executeFetchRequest:的调用需要很长时间才能完成,而且似乎确实在自己的线程上运行。为什么会导致UI挂起?

谢谢!

1 个答案:

答案 0 :(得分:5)

针对NSPersistentStoreCoordinator的任何活动都会导致一系列针对它的活动。如果您在一个线程上获取而另一个线程试图访问NSPersistentStoreCoordinator,则它将被阻止。

这可以通过以下两种方式之一解决:

  1. 减少提取以使块不明显。例如,获取块可以帮助减少此问题。
  2. 确保UI正在公开的数据已完全加载到内存中。这将阻止主线程尝试点击NSPersistentStoreCoordinator并被阻止。
  3. 根据应用程序和情况,这些实现中的一个或另一个(或两者)将消除此问题。

    在一天结束时,后台线程不是解决获取时间的银弹。如果你打算在后台线程上获取只是为了将它们放到主线程上,你会对性能感到失望。

    如果您要在后台线程上获取非UI用途,请考虑减小每次获取的大小或更改批量大小等,以减少获取时间本身。

    更新

    预热缓存并不像在OS X上那样在iOS上工作。您可以通过配置NSFetchRequest将对象完全加载到内存中,以便对象完全加载,关系是加载(如果需要),您的批量大小和获取大小足够大。当然,这需要与内存使用相平衡。