1

我有一个多线程应用程序,它同时进行了许多并发操作。当每个线程完成时,它会调用主线程上的两个方法之一

performSelectorOnMainThread:@selector(operationDidFinish:)
// and
performSelectorOnMainThread:@selector(operationDidFail:withMessage:)

当操作失败时,我启动一个显示错误消息的工作表并向用户显示 2 个按钮,“取消”和“重试”。这是我用来启动工作表的代码:

// failureSheet is a NSWindowController subclass

[NSApp beginSheet:[failureSheet window]
   modalForWindow:window
    modalDelegate:self
   didEndSelector:@selector(failureSheetDidEnd:returnCode:contextInfo:)
      contextInfo:nil];

问题是,如果 2 个并发操作同时失败,那么当前显示的工作表会被最后一个失败消息覆盖,然后用户的“重试”操作只会重试最后一个失败的操作。理想情况下,我想将这些故障表“排队”。如果 2 个操作同时失败,那么您应该看到 2 个工作表一个接一个,允许用户单独取消或重试它们。

我试过使用:

[NSApp runModalSessionForWindow:[failureSheet window]] 

这似乎做了我想要的,但在我的情况下不起作用。也许它不是线程安全的?

例如下面的代码工作......

- (void)displaySheet
{
    [NSApp beginSheet:[failureSheet window]
       modalForWindow:window
        modalDelegate:self
       didEndSelector:@selector(failureSheetDidEnd:returnCode:contextInfo:)
          contextInfo:nil];

    [NSApp runModalForWindow:[failureSheet window]];

    [NSApp endSheet:[failureSheet window]];

    [[failureSheet window] orderOut:nil];
}

// Calling this method from a button press works...
- (IBAction)testDisplayTwoSheets
{
    [self displaySheet];
    [self displaySheet];
}

但是,如果我有 2 个不同的线程操作在完成时调用 displaySheet(在主线程上),我只会看到一张纸,当我关闭它时,模态会话仍在运行,我的应用程序基本上被卡住了。

关于我做错了什么的任何建议?

4

2 回答 2

3

如果您想将它们排队,那么只需将它们排队即可。创建一个NSMutableArray结果对象(您可以使用操作,或故障表本身,或为您提供表信息的数据对象;任何方便)。在operationDidFinish:(它总是在主线程上运行,所以这里没有锁定问题),你会做这样的事情:

[self.failures addObject:failure];
if ([[self window] attachedSheet] == nil)
{
    // Only start showing sheets if one isn't currently being shown.
    [self displayNextFailure];
}

然后你会有:

- (void)displayNextFailure
{
    if ([self.failures count] > 0)
    {
        MYFailure runFailure = [self.failures objectAtIndex:0];
        [self.failures removeObjectAtIndex:0];
        [displaySheetForFailure:failure];
    }
}

最后failureSheetDidEnd:returnCode:contextInfo:,一定要打电话[self displayNextFailure]

也就是说,如果它经常发生的话,这可能是一个可怕的用户界面(很少有事情比一张一张地显示更糟糕)。我可能会寻找修改现有工作表以显示多个错误的方法。

于 2010-02-22T18:08:39.250 回答
0

我认为您没有正确使用“runModalForWindow:”命令。您不会同时使用 [NSApp beginSheet...] 和“runModalForWindow:”。一种用于文档模式(应用程序继续运行但带有工作表的窗口被锁定),一种用于应用程序模式(停止整个应用程序中的所有内容,直到关闭工作表)。你只想要应用程序模式对话框,所以这样做......

对于应用程序模式,仅使用以下内容启动窗口:

[[failureSheet window] center];
[NSApp runModalForWindow:[failureSheet window]];

将“确定”按钮和其他按钮与常规 IBAction 方法挂钩。当按下按钮时,它们会被调用。在 IBAction 方法中,您需要执行以下操作来关闭窗口并处理操作:

-(IBAction)okBtnPressed:(id)sender {
    [NSApp stopModal];
    NSLog(@"ok button");
    [[sender window] close];
}
于 2010-02-24T15:58:06.653 回答