【问题标题】:NSTextField + NSTimerNSTextField + NSTimer
【发布时间】:2014-07-15 08:51:20
【问题描述】:

我正在寻找一种在我的应用程序空闲时以NSTextField 的间隔显示字符串的方法。我知道使用sleep 的一种方法,尽管我认为这不是处理这个问题的最佳方法。我在想NSTimerscheduledTimerWithTimeInterval 可能是一个不错的方法,但我不知道该怎么做。

这是我的代码:

- (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

标签: objective-c cocoa nstimer nstextfield


【解决方案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 ++;

}

【讨论】:

【解决方案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 中的问题是我不想立即显示文本,而是根据需要显示。
猜你喜欢
  • 1970-01-01
  • 2012-04-10
  • 1970-01-01
  • 2021-01-17
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多