1

一度に多くの並行操作が実行されるマルチスレッドアプリケーションがあります。各スレッドが終了すると、メインスレッドの2つのメソッドのいずれかが呼び出されます

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(メインスレッド上)を呼び出す場合、1つのシートしか表示されず、それを閉じると、モーダルセッションはまだ実行されており、アプリは基本的にスタックしています。

私が間違っていることについて何か提案はありますか?

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]ください。

とはいえ、これが頻繁に発生する可能性がある場合、これは恐らく恐ろしいUIです(シートを次々に表示するよりも悪いことはほとんどありません)。複数のエラーを表示するように既存のシートを変更する方法をおそらく探します。

于 2010-02-22T18:08:39.250 に答える
0

「runModalForWindow:」コマンドを正しく使用していないと思います。[NSApp beginSheet ...]と「runModalForWindow:」の両方を同時に使用することはありません。1つはドキュメントモーダル(アプリケーションは実行を継続しますが、シートのあるウィンドウはロックされます)用で、もう1つはアプリケーションモーダル(シートが閉じられるまでアプリ全体のすべてを停止します)用です。アプリケーションのモーダルダイアログのみが必要なので、これを実行してください...

アプリケーションモーダルの場合、次の場合のみウィンドウを開始します。

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

「OK」ボタンなどを通常のIBActionメソッドに接続します。ボタンが押されると呼び出されます。IBActionメソッドでは、ウィンドウを閉じてアクションを処理するために、次のようなことを行う必要があります。

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