NSTextField + NSTimer
Posted
技术标签:
【中文标题】NSTextField + NSTimer【英文标题】: 【发布时间】:2014-07-15 08:51:20 【问题描述】:我正在寻找一种在我的应用程序空闲时以NSTextField
的间隔显示字符串的方法。我知道使用sleep
的一种方法,尽管我认为这不是处理这个问题的最佳方法。我在想NSTimer
scheduledTimerWithTimeInterval
可能是一个不错的方法,但我不知道该怎么做。
这是我的代码:
- (void)showTextAtInterval
NSTextField *textLabel;
[textLabel setStringValue:[NSString stringWithFormat:@"06/01/14"]];
sleep(5);
[textLabel setStringValue:[NSString stringWithFormat:@"Headlines"]];
....
编辑:试过了,但只静态显示“标题”。
[self startTimer];
- (void)startTimer
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(showTextAtInterval) userInfo:nil repeats:YES];
return;
- (void)showTextAtInterval
NSTextField *textLabel;
[textLabel setStringValue:[NSString stringWithFormat:@"06/01/14"]];
[textLabel setStringValue:[NSString stringWithFormat:@"Headlines"]];
【问题讨论】:
问题中显示的代码不会显示任何内容,但您说它显示“标题”。你的实际代码是什么? (编辑您的问题,不要将其作为评论发布。) @CRD,这是实际代码,here's the XCode project。当您运行项目时,它会显示“标题”。 在上面的代码中,textLabel
是一个未初始化的局部变量 showTextAtInterval
- 该代码不起作用。在您的实际代码中,textLabel
是该类的 IBOutlet
实例变量。像这样的细节问题。我将在下面添加一个答案。
不是玩魔鬼的拥护者,但是即使您将实例变量更改为 NSTextView *textLabel
而没有 IBOutlet
它仍然会做同样的事情。
关键是您的代码正在调用未初始化变量的方法,任何试图帮助您的人都会看到并指出问题所在。只是因为你写了它产生了输出,我才知道那不是你的代码。当您缩写代码以适应问题时,您必须小心不要引入错误或遗漏关键内容。 HTH
【参考方案1】:
您的代码有正确的想法,只是需要一些更改。
首先你发现不要使用sleep
- 这会完全停止当前线程,如果你从主线程调用它,就像你做的那样,基本上是你的应用程序。
有很多方法可以做到这一点。您选择的NSTimer
是一个不错的选择,因为您说您只想在程序空闲时显示消息,NSTimer
有一个invalidate
消息,您可以使用它来停止计时器当您的代码不再空闲时调用。
UI 更新必须在主线程上发生,并且不一定是同步的 - 从更新 UI 的方法返回时,UI 可能尚未反映更改。这就是为什么您只看到“标题”的原因,您在另一个之后有两个 UI 更新调用,第二个在您看到第一个效果之前完成。
您需要做的是:暂停,显示第一条消息,暂停,显示第二条消息,根据需要重复。因此,请更改您的代码,以便在第一次计时器触发时显示第一条消息,第二次触发时显示第二条消息,等等。您可以使用实例变量来跟踪应首先显示哪条消息。最好创建一个“空闲消息”类,其中包含启动和停止消息的方法,并将所有消息选择和显示逻辑保留在该类中,您的计时器和其他状态应该是该类的实例变量。确保所有 UI 更新都发生在主线程上,您可以通过确保在该线程上安排 NSTimer
来做到这一点(并将确保该逻辑的逻辑放在 start 方法中)。
HTH
【讨论】:
你能告诉我为什么它必须保留在主线程上吗?我并不质疑它的有效性,但是在使用使用动画的子视图时遇到了类似的问题。那种东西不能在后台运行似乎有点奇怪。 您提到的暂停计时器的标准方法是什么?谢谢 所有 UI 更新本身必须在主线程上,这是 Apple 的规则。您可以在其他线程上运行代码来确定 UI 应该如何更改、绘制到屏幕外缓冲区等,只是更新本身需要在主线程上。 您已经设置了正确的计时器,它是一个重复计时器。您不会暂停计时器,但是当您不再需要显示空闲消息时会使其无效(如果需要重新启动显示,请创建一个新计时器)。【参考方案2】:为了更正,我认为您应该添加一个私有变量并在showTextAtInterval
中进行切换。
- (void)showTextAtInterval
NSTextField *textLabel;
switch(iTimer)
case 0:
[textLabel setStringValue:[NSString stringWithFormat:@"06/01/14"]];
break;
case 1:
[textLabel setStringValue:[NSString stringWithFormat:@"Headlines"]];
break;
....
iTimer ++;
【讨论】:
私有变量,你的意思是这样的 > ***.com/a/844670/3257552?以及我将如何准确使用它。谢谢【参考方案3】:初始化你的计时器
-(void)awakeFromNib
[super awakeFromNib];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(showTextAtInterval) userInfo:nil repeats:YES];
并使用您的选择器:
- (void)showTextAtInterval
NSTextField *textLabel;
[textLabel setStringValue:[NSString stringWithFormat:@"06/01/14"]];
[textLabel setStringValue:[NSString stringWithFormat:@"Headlines"]];
....
【讨论】:
这项工作不会出现在awakeFromNib
中吗?我做了类似[self startTimer];
的操作,然后将NSTimer
放入-(void)startTimer
,但textLabel
只显示一个标签(最后一个标签,在本例中为“标题”)并且不会循环或任何其他内容。谢谢
@ctfd 然后你应该把[self startTimer]
放在awakeFromNib
中
请注意选择器不正确,来自 Apple 文档:“选择器应具有以下 签名:timerFireMethod:
(包括一个冒号,表示该方法需要一个参数). 计时器将自身作为参数传递”。
@nicael,将函数放在awakeFromNib
中的问题是我不想立即显示文本,而是根据需要显示。以上是关于NSTextField + NSTimer的主要内容,如果未能解决你的问题,请参考以下文章
根据 Font/Size 改变 NSTextField 的高度