2011-01-07 1 views
1

По какой-то причине, когда я нажимаю (удерживаю) на любом элементе управления, NSTimer в моем приложении замерзает и не срабатывает, пока я не отпущу кнопку мыши. Он просто не срабатывает, пока мышь нажата. Это нормально в течение коротких периодов времени, но оно также зависает, если у меня открыто всплывающее меню или выпадающее поле со списком.NSRunLoop зависает с NSTimer и любым входом

Я не уверен, есть ли что-то, что я пропустил, но похоже, что это неправильное поведение.

Я хочу, чтобы иметь возможность щелкнуть стрелку вниз NSPopUpButtonCell (или даже щелкнуть и удерживать NSTableView) без полного замораживания NSTimer (который перерисовывает NSView).

Любые комментарии/предложения будут оценены.

NSTimer добавлен в currentRunLoop с режимом NSDefaultRunLoopMode.

ответ

8

Пока мышь не работает, цикл запуска находится в NSEventTrackingRunLoopMode. Поэтому любое событие, которое не, принятое в очередь событий EventTracking, не будет обслуживаться до тех пор, пока runloop не вернется в соответствующий режим.

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

+0

Это сработало отлично. Спасибо за помощь! В качестве побочного вопроса, должны ли соединения (NSInputStream/NSOutputStream) находиться в NSConnectionReplyMode? – David

0

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

Решение должно использовать многопоточность, чтобы избежать этой привязки. Вот хороший блог на этой самой теме: http://blog.narent.com/?p=21

EDIT: после знакомства Дэйва альтернативу (и более элегантный ИМО) решение

Также смотрите:

+0

Многопоточности, безусловно, это * a * решение, но это не единственный. –

+0

Спасибо за исправление, хорошие вещи, чтобы знать. Ваше решение кажется намного приятнее! – Sam

+0

Спасибо. Запуск таймера во втором потоке - отличный вариант. Основная причина: * не * делать это, если вы используете таймер для запуска обновлений пользовательского интерфейса, так как вы не должны обновлять пользовательский интерфейс от чего-либо, кроме основного потока, который, по-видимому, использует этот парень (хотя вы мог бы вернуться к основной теме, я думаю ...). –

8

Вместо добавление два или более таймеров для различных runloops или использовать многопоточность (так как вы не будете иметь возможности обновить пользовательский интерфейс из другого потока) просто добавить таймер к NSRunLoopCommonModes:

NSTimer *myTimer = [NSTimer timerWithTimeInterval:RefreshInterval target:self selector:@selector(doWork) userInfo:nil repeats:YES]; 
    [[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes]; 
+0

perfect - это решило проблему для меня, когда поток пользовательского интерфейса был занят анимацией –