我正在用下面的代碼解析XML文件,並得到奇怪的行爲。我希望用戶能夠排隊多個需要解析的文件,並將它們放在一個單獨的線程上並串行完成。一切工作如預期如果我派遣一個隊列,並允許它完成點擊下一個。但是,如果我從第一個隊列開始並立即觸發另一個隊列,則第一個隊列完成解析,但通過調用Main Q來使UI更新和應用程序變得沒有響應(儘管我的微調繼續前進),但並未完成該塊。根據Xcode,CPU下降到0%,內存保持不變。dispatch_async沒有完成塊
我正在使用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;
}
我可以忽略什麼?
更新14年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變得反應遲鈍太儘管我的微調繼續)。
最後這裏是我HNArchivePointParser
類parsethisdata
其目的是只在後臺線程中使用。
-(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];
}
}
您應該發佈您看到的控制檯輸出 - 例如,您是否曾經看到「Main Q」被記錄? FWIW,它可能並不重要,但是你的'backgroundq'的懶惰創建不是線程安全的。假設'didSelectDownloadButtonForCell:'總是在主線程上調用,那應該不重要,但是誰知道?在HNArchivePointParser中,如果有任何依賴關係/聯鎖涉及,也很難說出什麼。如果這個類不是線程安全的,或者只是假設它是主線程的,或者它是在runloop的上下文中使用的,那麼可以解釋你所看到的行爲。 – ipmcc
@ipmcc感謝您的回覆!我已更新/添加代碼以幫助闡明更多的內容。我真的難以知道爲什麼這個代碼一次一個字,但當我嘗試排隊時,主線程鎖定了?我已經失去了很多睡眠! – kev
您是否在後臺線程上使用'performBlock:'進行與'NSPrivateQueueConcurrencyType' MOC的所有交互?如果您設置了一個異常斷點,您是否在回調從未發生的情況下點擊它? – ipmcc