Листы и долгосрочные задачи - PullRequest
0 голосов
/ 10 января 2011

Мне нужно выполнить сложную (то есть долгую) задачу после того, как пользователь нажмет на кнопку.Кнопка открывает лист, и длительная операция запускается с использованием dispatch_async и других приложений Grand Central.

Я написал код, и он отлично работает, но мне нужна помощь, чтобы понять, правильно ли я все сделалили если я проигнорировал (из-за своего незнания) любую потенциальную проблему.

Пользователь нажимает кнопку и открывает лист, блок содержит длинную задачу (в этом примере он запускает только 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];
}

1 Ответ

2 голосов
/ 08 марта 2011

У этого кода есть потенциальная проблема, когда он устанавливает значение текста статуса.В принципе, все объекты в 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.

...