0

用户单击按钮后,我需要运行一个复杂(即长)的任务。该按钮打开一个工作表,并使用 dispatch_async 和其他 Grand Central Dispatch 东西开始长时间运行的操作。

我已经编写了代码并且工作正常,但是我需要帮助来了解我是否正确地完成了所有操作,或者我是否忽略了(由于我的无知)任何潜在的问题。

用户单击按钮并打开工作表,该块包含长任务(在此示例中,它仅运行 for(;;) 循环该块还包含在任务完成时关闭工作表的逻辑。

-(IBAction)openPanel:(id)sender {
    [NSApp beginSheet:panel
       modalForWindow:[self window]
        modalDelegate:nil
       didEndSelector:NULL
          contextInfo:nil];

    void (^progressBlock)(void);
    progressBlock = ^{

        running = YES; // this is a instance variable

        for (int i = 0; running && i < 1000000; i++) {
            [label setStringValue:[NSString stringWithFormat:@"Step %d", i]];
            [label setNeedsDisplay: YES];
        }
        running = NO;
        [NSApp endSheet:panel];
        [panel orderOut:sender];

    };

    //Finally, run the block on a different thread.
    dispatch_queue_t queue = dispatch_get_global_queue(0,0);
    dispatch_async(queue,progressBlock);
}

该面板包含一个停止按钮,允许用户在任务完成之前停止任务

-(IBAction)closePanel:(id)sender {
    running = NO;
    [NSApp endSheet:panel];
    [panel orderOut:sender];
}
4

1 回答 1

2

此代码存在设置状态文本值的潜在问题。基本上,AppKit 中的所有对象都只允许从主线程调用,如果不是,它们可能会以奇怪的方式中断。您正在从运行全局队列的任何线程调用标签上的setStringValue:和方法。setNeedsDisplay:要解决此问题,您应该像这样编写循环:

for (int i = 0; running && i < 1000000; i++) {
    dispatch_async(dispatch_get_main_queue(), ^{
        [label setStringValue:[NSString stringWithFormat:@"Step %d", i]];
        [label setNeedsDisplay: YES];
    });
}

这将按照 AppKit 的预期从主线程设置标签文本。

于 2011-03-08T01:39:44.787 回答