2014-11-18 3 views
0

У меня есть объект NSStatusItem, который создается при запуске приложения (в AppDelegate.m). Этот объект «_statusBarItem» имеет приложенное к нему меню класса statusBarMenu, которое является подклассом класса NSMenu, но оно также имеет свойство _panelItem (класса NSMenuItem), созданное при создании экземпляра statusBarMenu, как вы можете видеть ниже.NSMenuItem пользовательский просмотр не обновляется

В statusBarItem.m

- (instancetype)initWithTitle:(NSString *)aTitle{ 
self = [super initWithTitle:aTitle]; 

if (self){ 

    _panelItem = [[NSMenuItem alloc]init]; 
    PanelViewController *panelViewController = [[PanelViewController alloc]init]; 
    panelViewController.menuDelegate = self; 
    _panelItem.view = panelViewController.view; 

    [self addItem:_panelItem]; 
} 
return self; 
} 

_panelItem имеет настраиваемое представление т.е. часы в метке (среди прочего). Это представление контролируется классом PanelViewController, в котором, когда метод viewDidLoad называется, вызывает метод tickTock: ниже. _upTime - это метка, показывающая часы/время. Он создается в файле .xib и подключен

- (void)tickTock:(id)obj{ 
NSTimeInterval timeInterval = 7.5 * 60 * 60; 

NSDate *timeToGetUp = [NSDate dateWithTimeInterval:timeInterval sinceDate:[NSDate date]]; 

NSDateFormatter *dateFormatter = [NSDateFormatter new]; 
[dateFormatter setDateFormat:@"hh:mm:ss"]; 

[_upTime setStringValue:[dateFormatter stringFromDate:timeToGetUp]]; 

[self.view setNeedsDisplay:YES]; 
[self.menuDelegate refreshView:self]; 

[self performSelector:@selector(tickTock:) withObject:NULL afterDelay:1.0]; 
} 

Как вы можете видеть, что тиканье: метод вызывается каждый 1.0 секунды. Это потому, что я хочу, чтобы метка обновлялась каждую секунду с новым временем. Однако метка не обновляется, хотя я вызываю setNeedsDisplay: для представления PanelViewController. Я думал, что это может быть потому, что я могу обновить неправильный вид, то есть я должен был обновить представление _panelItem. Поэтому я создал свойство menuDelegate и сделал statusBarMenu соответствующим показанному ниже протоколу.

@protocol PanelViewControllerMenuDelgate 

- (void)refreshView:(id)obj; 

@end 

Опять же refreshView: метод вызывается каждую секунду, он обновляет вид панели.

- (void)refreshView:(id)obj{ 
[_panelItem.view setNeedsDisplay:YES]; 
// [self itemChanged:_panelItem]; 
} 

Однако, это не обновляет представление и показывает новое значение метки. Я также попробовал метод itemChanged: to statusBarMenu obj (_statusBarItem), хотя он не имел никаких разных результатов.

Что я заметил, так это то, что если я закрою меню (щелкнув в другом месте) и снова открою его, он покажет новое значение часов/метки. Итак, что я делаю неправильно, или что я не делаю, что делает мнение неизменным. Должен ли я использовать какую-либо другую процедуру, чтобы обновлять представление _panelItem каждую секунду?

EDIT:

Я также заметил, что моделирование остановки работает, когда каждый нажмите _statusBarItem. Я просто добавил инструкцию NSLog в методе tickTock: и она прекратила печать в консоли, когда я открываю меню. Вероятно, поэтому представление не обновляется, так как приложение/Xcode приостанавливается, когда я нажимаю меню. Почему это происходит? Также как я могу остановить его?

ответ

0

Я только что столкнулся с этой проблемой несколько недель назад. В моем случае мой NSTimer не обновлял мой NSMenuItem. Я считаю, что ваша проблема происходит, потому что меню обновляется в другом цикле запуска для выполнения с задержкой. На этот вопрос отвечает fewplaces. Но это код, который нужно:

NSTimer interfaceUpdateTimer = [NSTimer timerWithTimeInterval:self.timerSettings.timerUpdateInterval//one second in your case 
             target:self 
                selector:@selector(tickTock:) 
             userInfo:nil 
             repeats:YES]; 
[[NSRunLoop currentRunLoop] addTimer:interfaceUpdateTimer forMode:NSRunLoopCommonModes]; 

Ключ NSRunLoopCommonModes. Просмотрите другие ответы, с которыми я связан; они уже объясняют это очень хорошо. Я думаю, это должно сделать трюк.


В качестве примечания, ни NSTimer, ни performSelector:withObject:afterDelay: являются гарантированно стрелять точно в указанное вами время. Поэтому, если вам нужна точность, не полагайтесь на них, чтобы рассказать о времени.Если достаточно близко достаточно, вы можете игнорировать эту заметку:)