我在显示较长的主线程动作的进度时遇到了一些麻烦(需要在主线程中)。
按一个按钮调用该动作。
-(void)getCSVExport:(id)sender{
...
NSString *filePath = [path stringByAppendingPathComponent:fileName];
NSData *csvData = [NSData dataWithContentsOfFile:filePath];
if (nil == csvData) {
_progressView.hidden = NO;
[self.view bringSubviewToFront:_progressView];
_progressView.progress = 0;
csvData = [self generateCSVExportForMonth:_monthToExportInt];
[csvData writeToFile:filePath atomically:YES];
_progressView.hidden = YES;
}
...
}
在funktion generateCSVExportForMonth:
中我正在使用_progressView.progress = newValue
更新进度。
我现在有两个问题:
1)当按下调用getCSVExport:
的按钮时,该按钮将保持高亮显示,直到通话结束。
2)progressView从不显示,更不用说自我更新了。
信息:根据设备的不同,通话需要0.5到2秒。
我出错的任何想法?
//编辑:带有backgroundThread的新版本:
[self.view bringSubviewToFront:_progressView];
_progressView.progress = 0;
[self performSelector:@selector(assignCSVData:) onThread:[NSThread new] withObject:csvData waitUntilDone:YES];
_progressView.hidden = YES;
和时间昂贵的电话:
-(void)assignCSVData:(NSData*)data{
data = [self generateCSVExportForMonth:_monthToExportInt];
}
这导致performSelector
来电时出现死锁。
答案 0 :(得分:2)
问题是您的主要线程被阻止了。这正是使用后台线程的原因,因为您不希望GUI冻结。
我不明白为什么解析CSV文件绝对的内容在主线程上。您必须在后台执行此操作(或使用冻结的GUI的糟糕用户体验)。
你有几个选择如何实际实现这样的东西。
使用NSObject
' s performSelectorInBackground:withObject:
将解析代码放在一个单独的方法中,然后使用以下命令在后台线程上启动它:
[self performSelectorInBackground:@selector(parseMethod) withObject:csvData];
在该方法结束时,您在主线程上调用一些方法来通知它解析已经完成。
[self performSelectorOnMainThread:@selector(parsingDone:) withObject:result waitUntilDone:NO];
使用Grand Central Dispatch (GCD)使用块语法在后台运行一些代码。如果你习惯使用Objective-C和Cocoa API,那么也很简单,但语法和语义要复杂一些。
使用NSOperation
和NSOperationQueue
。可能会为您的目的带来一些开销。虽然您也可以通过调用addOperationWithBlock
轻松地将新操作添加到队列中,而无需继承NSOperation
。