2011-01-10 3 views
0

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

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

Пользователь нажимает на кнопку и открывает лист, блок содержит длинную задачу (в данном примере это только бегает для (;;) цикла Блок также содержит логику, чтобы закрыть лист при завершении задачи.

-(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); 
} 

панель содержит кнопку Stop, которая позволяет пользователю остановить выполнение задачи до ее завершения

-(IBAction)closePanel:(id)sender { 
    running = NO; 
    [NSApp endSheet:panel]; 
    [panel orderOut:sender]; 
} 

ответ

2

Этот код имеет потенциальную проблему, где он устанавливает значение текста состояния. в основном все объекты в AppKit только разрешено называть f прокрутите основной поток и можете сломать странные способы, если они не будут. Вы вызываете методы 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.

Смежные вопросы