工作表和长时间运行的任务

发布于 2024-10-11 12:35:25 字数 1181 浏览 6 评论 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];
}

I need to run a complex (ie long) task after the user clicks on a button.
The button opens a sheet and the long running operation is started using dispatch_async and other Grand Central Dispatch stuff.

I've written the code and it works fine but I need help to understand if I've done everything correctly or if I've ignored (due to my ignorance) any potential problem.

The user clicks the button and opens sheet, the block contains the long task (in this example it only runs a for(;;) loop
The block contains also the logic to close the sheet when task completes.

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

The panel contains a Stop button that allows user to stop the task before its completion

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

独孤求败 2024-10-18 12:35:25

此代码存在一个潜在问题,即它设置状态文本的值。基本上,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 所期望的那样。

This code has a potential problem where it sets value of the status text. Basically all objects in AppKit are only allowed to be called from the main thread and can break in weird ways if they're not. You're calling the setStringValue: and setNeedsDisplay: methods on the label from whatever thread the global queue is running on. To fix this you should write the loop like so:

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

This will set the label text from the main thread as AppKit expects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文