我需要显示一个大文件的加载百分比,而不会阻塞用户界面。我进行了一些研究,找到了使用同一代码的使用Grand Central Dispatch的几种解决方案。但不幸的是,它对我不起作用。
要运行测试,我用一个while循环做了一个简单的例子,该循环用一个百分比更新了NSTextView。
当我单击开始按钮时,NSTextView用随机值更新一次,然后出现OSX旋转的色轮,并且该界面被阻止。当我单击“停止”按钮时,没有任何反应。缺点是,一旦循环结束,NSTextView将显示100,控制台将显示两次“ Stop”(停止)字样,就好像两次单击都将其保留在内存中一样。
由于几个答案使用的GCD代码似乎对其他人有用,所以我认为问题可能出在硬件上。我使用的是2009年运行OSX Mountain Lion的iMac。在终端中,物理和逻辑cpu的数量为:
sysctl hw.physicalcpu:2
sysctl hw.logicalcpu:2
在此先感谢您的帮助。这是我的代码:
@interface MainViewController ()
{
NSTextView *label;
NSButton *startButton;
NSButton *stopButton;
}
@end
@implementation MainViewController
- (void)loadView
{
NSView *aView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 500, 500)];
[aView setWantsLayer:YES];
aView.layer.backgroundColor = [NSColor lightGrayColor].CGColor;
self.view = aView;
label = [[NSTextView alloc] initWithFrame:NSMakeRect(30, 450, 100, 25)];
label.backgroundColor = [NSColor whiteColor];
label.textColor = [NSColor blackColor];
[label setEditable:NO];
label.font = [NSFont fontWithName:@"Arial" size:18.0];
[label setString:@"0"];
startButton = [[NSButton alloc] initWithFrame:NSMakeRect(30, 350, 60, 30)];
[startButton setBezelStyle:NSSegmentStyleTexturedRounded];
startButton.title = @"Start";
startButton.font = [NSFont fontWithName:@"Arial" size:14.0];
[startButton setTarget:self];
[startButton setAction:@selector(start)];
stopButton = [[NSButton alloc] initWithFrame:NSMakeRect(30, 300, 60, 30)];
[stopButton setBezelStyle:NSSegmentStyleTexturedRounded];
stopButton.title = @"Stop";
stopButton.font = [NSFont fontWithName:@"Arial" size:14.0];
[stopButton setTarget:self];
[stopButton setAction:@selector(stop)];
[self.view addSubview:label];
[self.view addSubview:startButton];
[self.view addSubview:stopButton];
}
- (void)start
{
NSLog(@"Start");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
{
//Background thread
float total = 200000;
for(int i = 0; i < total; i++)
{
//do some hard work here...
float percent = ((float)i/total) * 100;
dispatch_async(dispatch_get_main_queue(), ^(void)
{
//Main thread (UI update)
[label setString:[NSString stringWithFormat:@"%.f", percent]];
[label setNeedsDisplay:YES];
});
}
});
NSLog(@"END : Start");
}
- (void)stop
{
NSLog(@"Stop");
}
答案 0 :(得分:0)
我怀疑您的样本中的for
循环非常热-即它几乎以最快的速度在您的主队列上调用dispatch_async
,这使UI更新线程饱和。
这是一个非常愚蠢的建议,但是您可以尝试在分派到主线程之前进行sleep
调用吗?只需10毫秒左右。这样可以让UI时间在下一次异步调用点击之前进行更新。
如果您在注释“在这里努力工作”的代码花费了足够的时间来允许UI更新并接收其他事件,那么您就可以了。我认为这只是使您的用户界面变得饱和的硬编码示例。