0

ユーザーがボタンをクリックした後、複雑な(つまり長い)タスクを実行する必要があります。ボタンはシートを開き、dispatch_asyncおよびその他のGrandCentralDispatchのものを使用して長時間実行操作が開始されます。

私はコードを書きましたが、それは正常に機能しますが、すべてを正しく実行したかどうか、または(無知のために)潜在的な問題を無視したかどうかを理解するための助けが必要です。

ユーザーがボタンをクリックしてシートを開くと、ブロックには長いタスクが含まれます(この例では、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 に答える