dispatch_async未完成阻止

时间:2014-01-21 23:06:22

标签: ios7 grand-central-dispatch

我正在使用以下代码解析XML文件,并且我的行为很奇怪。我希望用户能够排队需要解析的多个文件,并将它们放在一个单独的线程上并按顺序完成。一切都按预期工作如果我发送一个队列并允许它在点击下一个之前完成。

但是,如果我开始第一个并立即触发另一个第一个队列完成解析但是没有通过调用主Q来完成UI更新并且应用程序变得没有响应(尽管我的微调器继续运行)。根据Xcode,CPU降至0%,内存保持不变。

我正在使用CoreData并在相应的线程上创建一个新的MOC。再一次,如果我一次做一个它工作正常,如果我注释掉解析并且只做一个循环我可以排队并且它可以工作,在完成之后开始下一个循环。

这篇文章提到主要线程被阻止,但如果我运行一个重复计时器并在队列运行时将其记录下来,那么一切都很好。

参考 - > dispatch_async block on main queue is never execeuted

-(void)didSelectDownloadButtonForCell:(FieldsCell *)cell{

    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(ticktock) userInfo:nil repeats:YES];

    cell.shouldBeAnimating = YES;
    cell.ActivityIndicator.hidden = NO;
    [cell.ActivityIndicator startAnimating];
    cell.DownloadBtn.hidden = YES;
    cell.PartialDownloadBtn.hidden = YES;

    HNField *field = [HNField fieldWithField_id:[NSNumber numberWithInteger:cell.tag]];
    NSString *xmlfile = [NSString stringWithFormat:@"%@%@",[field.name stringByReplacingOccurrencesOfString:@" " withString:@""],@".xml"];
    NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:xmlfile];
    __block NSData *data = [[NSData alloc] initWithContentsOfFile:path];


    //load up core data with demo xml file
    dispatch_async(self.backgroundq, ^(void){
        NSLog(@"Block dispatched");
        HNArchivePointParser *aParser = [[HNArchivePointParser alloc]init];
        [aParser parsethisdata:data];
        NSLog(@"Parser has finished");

 //running simple loops works just fine.
//for (int i = 1;  i < 1000; i++) {
//    NSLog(@"%d - %@",i,cell);
//}


        dispatch_async(dispatch_get_main_queue(), ^{
           NSLog(@"THIS IS THE MAIN Q");
            cell.shouldBeAnimating = NO;
            [cell.ActivityIndicator stopAnimating];
            cell.ActivityIndicator.hidden = YES;
            cell.DownloadBtn.hidden = YES;
            cell.PartialDownloadBtn.hidden = NO;
        });
        NSLog(@"background Q completed");
    });
}

-(void)ticktock{
    NSLog(@"tick");
}

我懒洋洋地得到我的队列。

-(dispatch_queue_t )backgroundq{
    if (!_backgroundq) {
        NSLog(@"NEW");
        _backgroundq = dispatch_queue_create("com.myapp....", DISPATCH_QUEUE_SERIAL);
    }

    if ([NSThread isMainThread]) {
        NSLog(@"RETURNED on Main Thread");
    }else NSLog(@"RETURNED on the wrong thread");

    return _backgroundq;
}

我有什么可以忽略的?

更新2014年1月23日 假设总是在主线程上调用didSelectDownloadButtonForCell:是正确的,我添加了一些代码来确认它。 我还更新了上面的代码,这里是我的日志,当我点击一个按钮并等待它完成后再点击下一个。

2014-01-23 10:02:08.866[1362:70b] NEW
2014-01-23 10:02:08.867[1362:70b] RETURNED on Main Thread
2014-01-23 10:02:08.868[1362:f03] Block dispatched
2014-01-23 10:02:09.864[1362:70b] tick
2014-01-23 10:02:10.864[1362:70b] tick
2014-01-23 10:02:11.864[1362:70b] tick
2014-01-23 10:02:12.864[1362:70b] tick
2014-01-23 10:02:13.719[1362:f03] Parser has finished
2014-01-23 10:02:13.719[1362:70b] THIS IS THE MAIN Q
2014-01-23 10:02:13.719[1362:f03] background Q completed
2014-01-23 10:02:13.863[1362:70b] tick
2014-01-23 10:02:14.864[1362:70b] tick
2014-01-23 10:02:15.864[1362:70b] tick
more ticks.........

这是我点击同一个按钮并在点击下一个按钮之前等待2个滴答的日志

2014-01-23 10:10:32.484[1417:70b] NEW
2014-01-23 10:10:32.485[1417:70b] RETURNED on Main Thread
2014-01-23 10:10:32.486[1417:f03] Block dispatched
2014-01-23 10:10:33.482[1417:70b] tick
2014-01-23 10:10:34.481[1417:70b] tick
2014-01-23 10:10:37.304[1417:f03] Parser has finished
2014-01-23 10:10:37.304[1417:f03] background Q completed

计时器在主线程上,所以很明显它的锁定(尽管我的微调器继续,UI也没有响应)。

最后,我的parsethisdata课程中的HNArchivePointParser是{strong>仅在后台主题中使用。

-(void)parsethisdata:(NSData *)data{

    self.clientid = [[NSUserDefaults standardUserDefaults] objectForKey:@"UserId"];

    //create a MOC in background thread
    AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication]delegate];
    self.MOC = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [self.MOC setPersistentStoreCoordinator:[app persistentStoreCoordinator]];
    self.theResponseId = 0;

    if (!self.parser) {
        self.parser = [[NSXMLParser alloc]initWithData:data];
        [self.parser setDelegate:self];
        [self.parser parse];
    }
}

1 个答案:

答案 0 :(得分:0)

很难确切地知道是什么导致了您的麻烦,但有一件事是肯定的:您应该在提交给NSPrivateQueueConcurrencyType的块内的NSMainQueueConcurrencyTypeperformBlock:托管对象上下文中完成所有工作或performBlockAndWait:

相反,如果您只想说,“我保证此MOC上的所有操作都将通过一个线程完成,这是我的责任”,您应该使用NSConfinementConcurrencyType

我不能说出为什么它没有barf和死亡的原因,如果你不使用它们(它会很容易检查),但docs are pretty clear关于此。

对于这些事情,GCD通常会非常聪明。例如,如果你调用performBlockAndWait:,它会在大多数情况下最终使用调用线程来执行实际执行,它只会等到该队列中没有其他人正在执行,所以它不会像是自动执行涉及一些巨大的转换成本。

假设MOC对于该解析操作是私有的,则没有理由不在提交给performBlock:的单个块中执行整个解析操作。