我希望创建一个循环,每十秒递增一个整数,并执行一百次。但是当我使用这段代码时:
- (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
。发生了什么事?
答案 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]; });