在某个视图中,我希望在触发时间基于NSTimeIntervals数组(我保留为NSArray保持双值)时触发某个方法。
所以我有一个根据相关时间执行相关操作的方法,并且在此方法中,我调用相同的方法(递归地)在下一个预定时间再次触发:
-(void) actionMethod:(int)someDataINeed {
//do something and then...
if (someDataINeed == someDefinitionIHaveToBreakTheLoop) {
return;
}
double nextFire = [self aMethodThatCalculatesTheNextFiringTime];
NSNumber * nextDataINeed = [NSNumber numberWithInt:someDataINeed+1];
NSTimer * aTimer = [NSTimer scheduledTimerWithTimeInterval:nextFire
target:self
selector:@selector(actionMethod:)
userInfo:nextDataINeed
repeats:NO];
}
嗯......它不起作用(如果确实如此,我想我不会问它......)。 当我对它进行NSLog时,似乎时间根本没有运行,并且在某种循环中调用定时器而不是根据我定义的时间“被触发”。 nextFire双数据是正确的(根据我的定义)。
如果我错了,如果有人能指导我应该如何执行这类行动,我将不胜感激。
如果我做对了,但只是写错了,那么抓住我的“虫子”的眼睛也会受到赞赏......
答案 0 :(得分:1)
我猜你正在使用ARC。您不会将计时器存储在强变量中,因此它会在触发之前释放。创建一个ivar" NSTimer * aTimer",然后在实例化计时器时使用它而不是局部变量(我在这里胡言乱语,因为我不记得runLoop是否在其计划时保留它 - 可能但是将此保留为完整性,因为如果出于任何原因,您应该在计时器上调用invalidate,并弹出"等等。
此外,您的计时器还会发送消息:actionMethod:(NSSTimer *)本身,但您的操作方法需要一个int。你需要调和它。
编辑:
将actionMethod更改为以下格式:
-(void)actionMethod:(id)something
{
int foo = 0;
if([something isKindOfClass:[NSNumber class]]) {
foo = [foo intValue];
} else
if([something isKindOfClass:[NSTimer class]]) {
foo = ... // however you get your value
} else
assert(!"Yikes! Wrong class");
}
...
然后你可以发送一个NSNumber或让计时器用计时器调用它。您可以从NSNumber中提取int,或从计时器中获取值:
答案 1 :(得分:1)
当您安排NSTimer实例时,运行循环会保留计时器,因此无需担心自己保留(ARC或不是)。
计时器还会保留其目标,因此您不必担心首先释放目标的情况。但是,如果目标是视图,则在从视图层次结构中删除后,它可能会收到计时器消息。在这种情况下,您将要忽略该消息。
您可以通过以下两种方式处理:
在actionMethod
中,请务必检查您是否仍要执行此操作。如果没有,请忽略该消息并清除所有内容。
保留对计时器实例的引用,并在不再希望接收计时器消息时调用[timer invalidate]
。
如果您可以确定目标始终存在并且始终可以接收消息,则无需执行任何操作。例如,您的应用委托对象将在您的应用程序的生命周期内使用。
您无法设置计时器来调用任何对象上的任何方法。计时器方法必须只接受一个参数,即发送消息的NSTimer实例。您已定义actionMethod:
以获取int
,它将实际编译并执行,但是当计时器触发并调用该方法时,someDataINeed
的值将是- (void)actionMethod:(NSTimer *)timer
的内存地址。 NSTimer对象。这不是很有用。
您需要以这种方式定义方法:
someDataINeed
要获取 NSNumber *number = [timer userInfo];
int someDataINeed = [number intValue];
值,可以将其保存为计时器userInfo中的NSNumber。它只是为了你可以添加一些数据到计时器。
nextDataINeed
创建计时器时,可以将 currentTimer = [NSTimer scheduledTimerWithTimeInterval:nextFire
target:self
selector:@selector(actionMethod:)
userInfo:[NSNumber numberWithInt:nextDataINeed]
repeats:NO];
包装到NSNumber中并以这种方式设置userInfo:
aMethodThatCalculatesTheNextFiringTime
您需要使用NSNumber,因为userInfo必须是对象。
如果应用上述方法无法解决问题,那么要检查的一件事是nextFire
返回自 now 以来的时间间隔,而不是自参考日期以来。如果您希望计时器在三秒内触发,则3.0
的值必须为timeIntervalSinceReferenceDate
。如果你不小心打电话给{{1}},你会得到一个巨大的数字,而计时器将安排在未来几年开火。