0

我在显示较长的主线程操作的进度时遇到了一些麻烦(需要在主线程中)。

通过按下按钮调用该操作。

-(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;
    }
    ...
}

在功能内,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调用时出现死锁。

4

1 回答 1

2

问题是你的主线程被阻塞了。这正是将后台线程用于需要更长时间的事情的原因,因为您不希望 GUI 冻结。

我不明白为什么像解析 CSV 文件这样的东西绝对必须在主线程上。您必须在后台执行此操作(或忍受冻结 GUI 的糟糕用户体验)。

你有几个选择如何实际实现这样的东西。

  • 使用NSObject'sperformSelectorInBackground:withObject:

    将解析代码放在一个单独的方法中,并使用以下方法在后台线程上启动它:

    [self performSelectorInBackground:@selector(parseMethod) withObject:csvData];
    

    在该方法结束时,您调用主线程上的某个方法来通知它解析已完成。

    [self performSelectorOnMainThread:@selector(parsingDone:) withObject:result waitUntilDone:NO];
    
  • 使用Grand Central Dispatch (GCD)使用块语法在后台运行一些代码。如果您习惯于 Objective-C 和 Cocoa API,也很简单,但语法和语义会稍微复杂一些。

  • 使用NSOperationNSOperationQueue。对于您的目的,可能会有一点开销。尽管您也可以通过调用addOperationWithBlock而不使用子类轻松地将新操作添加到队列中NSOperation

于 2013-04-03T12:13:25.713 回答