工作表和长时间运行的任务
我需要在用户单击按钮后运行一个复杂(即很长)的任务。 该按钮打开一个工作表,并使用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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
此代码存在一个潜在问题,即它设置状态文本的值。基本上,AppKit 中的所有对象都只允许从主线程调用,否则可能会以奇怪的方式中断。您可以从运行全局队列的任何线程调用标签上的
setStringValue:
和setNeedsDisplay:
方法。要解决这个问题,您应该像这样编写循环:这将从主线程设置标签文本,正如 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:
andsetNeedsDisplay:
methods on the label from whatever thread the global queue is running on. To fix this you should write the loop like so:This will set the label text from the main thread as AppKit expects.