NSTextView не обновляется с помощью Grand Central Dispatch - PullRequest
0 голосов
/ 08 марта 2019

Мне нужно показать процент загрузки большого файла без блокировки пользовательского интерфейса. Я провел небольшое исследование и нашел несколько решений, использующих Grand Central Dispatch, с одним и тем же кодом. Но, к сожалению, это не работает для меня.

Для запуска тестов я сделал простой пример с циклом while, который обновляет NSTextView с процентом.

Когда я нажимаю кнопку запуска, NSTextView обновляется один раз со случайным значением, затем появляется вращающееся цветовое колесо OSX и интерфейс блокируется. Когда я нажимаю кнопку Стоп, ничего не происходит. К минусам, когда цикл заканчивается, NSTextView отображает 100, а консоль дважды отображает слово «Стоп», как если бы она сохранила в памяти два сделанных клика.

Поскольку в нескольких ответах используется один и тот же код GCD, который, похоже, работает для других людей, я предположил, что, возможно, проблема в аппаратном обеспечении. Я работаю на iMac с 2009 года под управлением OSX Mountain Lion. В терминале количество физических и логических процессоров:

sysctl hw.physicalcpu: 2

sysctl hw.logicalcpu: 2

Заранее спасибо за помощь. Вот мой код:

@interface MainViewController ()
{
    NSTextView *label;
    NSButton *startButton;
    NSButton *stopButton;
}
@end

@implementation MainViewController

- (void)loadView
{
    NSView *aView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 500, 500)];
    [aView setWantsLayer:YES];
    aView.layer.backgroundColor = [NSColor lightGrayColor].CGColor;
    self.view = aView;

    label = [[NSTextView alloc] initWithFrame:NSMakeRect(30, 450, 100, 25)];
    label.backgroundColor = [NSColor whiteColor];
    label.textColor = [NSColor blackColor];
    [label setEditable:NO];
    label.font = [NSFont fontWithName:@"Arial" size:18.0];
    [label setString:@"0"];

    startButton = [[NSButton alloc] initWithFrame:NSMakeRect(30, 350, 60, 30)];
    [startButton setBezelStyle:NSSegmentStyleTexturedRounded];
    startButton.title = @"Start";
    startButton.font = [NSFont fontWithName:@"Arial" size:14.0];
    [startButton setTarget:self];
    [startButton setAction:@selector(start)];

    stopButton = [[NSButton alloc] initWithFrame:NSMakeRect(30, 300, 60, 30)];
    [stopButton setBezelStyle:NSSegmentStyleTexturedRounded];
    stopButton.title = @"Stop";
    stopButton.font = [NSFont fontWithName:@"Arial" size:14.0];
    [stopButton setTarget:self];
    [stopButton setAction:@selector(stop)];

    [self.view addSubview:label];
    [self.view addSubview:startButton];
    [self.view addSubview:stopButton];
}

- (void)start
{
    NSLog(@"Start");

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
    {
        //Background thread
        float total = 200000;

        for(int i = 0; i < total; i++)
        {
            //do some hard work here...
            float percent = ((float)i/total) * 100;

            dispatch_async(dispatch_get_main_queue(), ^(void)
            {
                //Main thread (UI update)
                [label setString:[NSString stringWithFormat:@"%.f", percent]];
                [label setNeedsDisplay:YES];
            });
        }
    });

    NSLog(@"END : Start");
}

- (void)stop
{
    NSLog(@"Stop");
}

1 Ответ

0 голосов
/ 21 июня 2019

Я подозреваю, что ваш for цикл в вашем образце очень горячий - т.е.он вызывает dispatch_async в вашей основной очереди почти так быстро, как только может, что насыщает поток обновления пользовательского интерфейса.

Это действительно глупое предложение, но не могли бы вы попытаться сделать вызов sleep доотправить на основной поток?Всего 10 мс или что-то.Это позволило бы обновлению пользовательского интерфейса до следующего асинхронного вызова.

Если код, в котором вы прокомментировали «выполнять тяжелую работу здесь», занимает достаточно времени, чтобы пользовательский интерфейс мог обновить и получить другие события, тогда вывсе должно быть в порядке.Я думаю, что это просто ваш жестко запрограммированный образец, который насыщает пользовательский интерфейс.

...