在循环中重复更改文本字段仅显示一个最终值

时间:2013-11-29 07:20:14

标签: objective-c cocoa loops nstextfield

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

- (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。发生了什么事?

2 个答案:

答案 0 :(得分:0)

您的陈述:

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

延迟你的循环 - 相反,对于循环的每次迭代,它都会调度一个定时器来调用loopTest:,这是你定义为什么都不做的方法。

要使用计时器来延迟循环,您需要计划执行循环剩余部分的方法。换句话说,一个非循环方法,它执行相当于循环的一次迭代,然后安排时间来执行余数。

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

- (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)是另一种,在这种情况下具有传递三个值的优点:当前索引,限制和延迟;更容易。

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

- (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方法和类型的详细信息,请参阅文档。

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

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

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

HTH。

答案 1 :(得分:-1)

试试这个

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,i * NSEC_PER_SEC),                    dispatch_get_main_queue(),^ {       yourtextfield.text = [NSString stringWithFormat:@&#34;%d&#34;,i];     });