循环更改文本字段仅显示一个最终值 [英] Changing text field repeatedly in a loop only displays one final value

查看:191
本文介绍了循环更改文本字段仅显示一个最终值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望创建一个循环,该循环每十秒递增一个整数,并执行一百次。但是当我使用以下代码时:

I wish to create a loop that increments an integer every ten seconds, and does this one hundred times. But when I use this code:

- (IBAction)loopTest:(id)sender {

}

- (IBAction)beginLoop:(id)sender {
  for (i=0;i<100 ;i++ ) {
    testingLoops++;
    NSString *feed = [NSString stringWithFormat: @"%d", testingLoops];
    self.feedLabel.stringValue = feed;
    [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(loopTest:)           userInfo:nil repeats:NO];
}

}

应用程序仅将整数显示为马上100。我有它,这样当我按下按钮时它就会运行 beginLoop

the application just displays the integer as 100 straight away. I have it so that it runs the beginLoop when I press a button. What's going on?

推荐答案

您的声明:

[NSTimer scheduledTimerWithTimeInterval:10
                                 target:self
                               selector:@selector(loopTest:)
                               userInfo:nil
                                repeats:NO];

not 不会延迟循环-而是每次循环迭代安排计时器调用 loopTest:,您已定义为什么都不做的方法。

does not delay your loop - rather for every iteration of the loop it schedules a timer to call loopTest:, a method you've defined to do nothing.

使用计时器要延迟循环,您需要安排执行循环其余部分的方法。换句话说,一种非循环方法等效于循环的一次迭代,然后安排执行剩余时间的时间。

To use a timer to delay a loop you need to schedule a method which performs the remainder of the loop. In other words a non-loop method which performs the equivalent of one iteration of your loop and then schedules a time to perform the remainder.

按照您的方法进行操作,但切换到使用由 performSelector:withObject:afterDelay 提供的隐式计时器,因为它在这里更方便,这给了我们:

Following your approach, but switching to use an implicit timer provided by performSelector:withObject:afterDelay as it is more convenient here, this gives us:

- (IBAction)beginLoop:(id)sender
{
   // start "loop"
   // note we only pass the current index and not the limit or delay
   // as there is no performSelector version which directly supports
   // passing three values to the selector
   [self doLoopIndex:@0];
}

- (void) doLoopIndex:(NSNumber *)objIndex
{
   // extract int from NSNumber - we use the later as the argument type so we can use performSelector below
   int index = objIndex.intValue;

   // do the work of one iteration
   NSString *feed = [NSString stringWithFormat: @"%d", index];
   self.feedLabel.stringValue = feed;

   // increment "loop" counter and schedule next iteration if needed
   // note the use of @(index) to create an NSNumber as an object is required
   index++;
   if (index < 100)
      [self performSelector:@selector(doLoopIndex:) withObject:@(index) afterDelay:1];
}

这不是实现目标的唯一方法。使用块和 Grand Central Dispatch(GCD)是另一种方法,在这种情况下,其优点是传递三个值:当前索引,限制和延迟;

This is not the only way to achieve your goal. Using blocks and "Grand Central Dispatch" (GCD) is another and in this case has the advantage that passing three values: current index, limit and delay; is easier.

例如,具有延迟的一般循环可能写为:

For example, a general loop with delay might be written as:

- (void) doLoop:(int)index                      // starting index
          limit:(int)limit                      // limit
          delay:(NSTimeInterval)delayInSeconds  // delay each iteration
           body:(void (^)(int))body             // block for loop body
{
   // invoke the body block
   body(index);

   // increment index and schedule next "iteration" if needed
   index++;
   if (index < 100)
   {
      dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
      dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
      {
         [self doLoop:index limit:limit delay:delayInSeconds body:body];
      });
   }
}

有关dispatch_X方法和方法的详细信息,请参见文档。

See the documentation for the details of the dispatch_X methods and types.

这可能看起来更复杂,但这是因为它更通用。使用上面的代码,您的特定循环变为:

This might look more complicated, but that is because it is more general. Using the above your particular loop becomes just:

- (IBAction)beginLoop:(id)sender
{
   [self doLoop:0 limit:100 delay:1 body:^(int index)
    {
       NSString *feed = [NSString stringWithFormat: @"%d", index];
       self.feedLabel.stringValue = feed;
    }];
}

上述方法中的哪一种,或使用显式计时器作为原始代码,适合您的用例就是您的选择-没有单一的正确答案。

Which of the above approaches, or using an explicit timer as your original code did, is appropriate for your use case is your choice - there is no single "right" answer.

HTH。

这篇关于循环更改文本字段仅显示一个最终值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆