多次获取请求导致应用程序冻结

时间:2014-02-15 17:11:33

标签: ios objective-c multithreading core-data

我的问题如下:我的UI中有三个按钮,它们将触发具有不同参数的相同获取请求。如果我按顺序按下这些按钮,但在每个按钮之间等待一两秒,一切正常。如果我更快地做到这一点,该应用程序将冻结。调试器显示了一个互斥锁。现在,我正在使用带有mainMOC和backgroundMOC的CoreData,我找不到我做错了什么以及如何解决我的问题。

我检查了类似的问题,但所有建议的解决方案对我都不起作用。 以下是我认为涉及此问题的代码:

@interface LooksDataSource ()

@property (nonatomic,strong) NSManagedObjectContext *mainContext;
@property (nonatomic,strong) NSManagedObjectContext *backgroundContext;
@property (nonatomic,strong) NSFetchedResultsController *fetchedResultsController;
@end

@implementation LooksDataSource

-(id) init {
 @throw [NSException exceptionWithName:@"LooksDataSource exception" reason:@"please use initWithManagedObjectContext" userInfo:nil];
}

-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

-(id) initWithManagedObjectContext: (NSManagedObjectContext *) context {

    self = [super init];
    if (self) {
        self.mainContext = context;
        dispatch_async(dispatch_get_global_queue(0, 0), ^(){
        self.backgroundContext = [[NSManagedObjectContext alloc] init];
        self.backgroundContext.persistentStoreCoordinator = self.mainContext.persistentStoreCoordinator;
        });        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(repoUpdated:) name:NSManagedObjectContextDidSaveNotification object:self.mainContext];
    }
    return self;
}

-(void) findLooksWithPredicate: (NSPredicate *) predicate {
    if (![predicate isEqual:self.fetchedResultsController.fetchRequest.predicate]) {
        [self performNewRequestwithPredicate:predicate];
    }
    else {
        //return results of latest fetch
        id <NSFetchedResultsSectionInfo> sectionZeroInfo = [self.fetchedResultsController sections][0];
        NSMutableArray *objectIDsForResults = [NSMutableArray array];
        for (NSManagedObject *aResult in [sectionZeroInfo objects]) {
            [objectIDsForResults addObject:aResult.objectID];
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            //re-create the MOs referred to in objectIDsForResults in the "main" MOC
            NSMutableArray *resultsOnMainMOC = [NSMutableArray array];
            for (NSManagedObjectID *aResultID in objectIDsForResults) {
                [resultsOnMainMOC addObject:[self.mainContext objectWithID:aResultID]];
            }
            NSArray *results = [NSArray arrayWithArray:resultsOnMainMOC];
            [self.delegate looksDataSource:self
                       returnedResults:results];
        });
    }
}

感谢大家的帮助

1 个答案:

答案 0 :(得分:1)

正如@Wain所说,目前还不清楚你在这里如何使用线程以及背景提取的位置。

有人说......

您创建背景MOC的方式不是线程安全的:
您创建使用线程限制并发类型的托管对象上下文 这意味着您必须在创建的线程上使用此上下文 ONLY 由于您使用GCD创建了此上下文,因此您不知道哪个线程创建了它,也不能让该线程保持活动状态。

问题的解决方案是@Wain所说的:对于您在后台发送的每个操作,创建一个受限的托管对象上下文,使用它,并在操作结束时确保您处理它:

dispatch_async(dispatch_get_global_queue(0, 0), ^(){
    NSManagedObjectContext* context = [[NSManagedObjectContext alloc] init];
    context.persistentStoreCoordinator = self.mainContext.persistentStoreCoordinator;
    //Make the fetch and export results to main thread
});