Ios 当触发时间可能发生变化时,如何使用要触发的自动计划动作?
在某个视图中,我希望在触发时间基于NSTimeInterval数组时触发某个方法(我将其作为NSArray保留双值) 因此,我有一个方法,它根据相关的时间执行相关的操作,在这个方法中,我(递归地)调用相同的方法,以便在下一个计划的时间再次触发:Ios 当触发时间可能发生变化时,如何使用要触发的自动计划动作?,ios,nstimer,nstimeinterval,Ios,Nstimer,Nstimeinterval,在某个视图中,我希望在触发时间基于NSTimeInterval数组时触发某个方法(我将其作为NSArray保留双值) 因此,我有一个方法,它根据相关的时间执行相关的操作,在这个方法中,我(递归地)调用相同的方法,以便在下一个计划的时间再次触发: -(void) actionMethod:(int)someDataINeed { //do something and then... if (someDataINeed == someDefinitionIHaveToBreakT
-(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];
}
嗯。。。它不起作用(如果有,我想我不会问它……)。
当我记录它时,似乎时间根本没有运行,计时器在某种循环中被调用,并且没有根据我定义的时间“被触发”。nextFire双精度数据是正确的(根据我的定义)
如果我搞错了,如果有人能告诉我应该如何执行这类操作,我将不胜感激
如果我做对了,但只是写错了,一双能抓住我“错误”的眼睛也会很感激…我猜你在使用ARC。您没有将计时器存储在强变量中,因此它会在触发之前释放。创建一个ivar“NSTimer*aTimer”,然后在实例化计时器时使用该变量而不是局部变量(我在这里胡说,因为我不记得runLoop是否在其预定时间保留它-可能是为了完整性而将其保留在这里,因为如果出于任何原因您被“弹出”等,您应该在计时器上调用invalidate) 计时器本身也会发送消息:actionMethod:(NSSTimer*),但您的action方法需要一个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,或者从计时器中获取一个值:这不是内存管理问题
当您计划NSTimer实例时,运行循环会保留计时器,因此无需担心自己是否会保留它(ARC)
计时器还保留其目标,因此您不必担心目标首先被释放的情况。但是,如果目标是一个视图,则它可能会在从视图层次结构中删除后收到计时器消息。在这种情况下,您将希望忽略该消息
您可以通过两种方式处理此问题:
操作方法中
,确保检查是否仍要执行该操作。如果没有,请忽略该消息,让一切都清理干净[timer invalidate]
actionMethod:
来获取一个int
,它将实际编译和执行,但是当计时器触发并调用该方法时,somedatained
的值将是NSTimer对象的内存地址。这不是很有用
您需要这样定义您的方法:
- (void)actionMethod:(NSTimer *)timer
currentTimer = [NSTimer scheduledTimerWithTimeInterval:nextFire
target:self
selector:@selector(actionMethod:)
userInfo:[NSNumber numberWithInt:nextDataINeed]
repeats:NO];
要获取somedatained
值,可以将其保存为计时器用户信息中的NSNumber。它就在那里,以便您可以向计时器添加一些数据
NSNumber *number = [timer userInfo];
int someDataINeed = [number intValue];
创建计时器时,您可以将nextDatained
包装成一个NSNumber,并通过以下方式设置用户信息:
- (void)actionMethod:(NSTimer *)timer
currentTimer = [NSTimer scheduledTimerWithTimeInterval:nextFire
target:self
selector:@selector(actionMethod:)
userInfo:[NSNumber numberWithInt:nextDataINeed]
repeats:NO];
您需要使用NSNumber,因为userInfo必须是一个对象
可能的错误
如果应用上述方法无法解决问题,那么需要检查的一件事是,计算下一次启动时间的
方法返回的是从现在开始的时间间隔,而不是从参考日期开始的时间间隔。如果希望计时器在三秒内启动,nextFire
的值必须是3.0
。如果您不小心拨打了timeIntervalSinceReferenceDate
,您将得到一个巨大的数字,并且计时器将在未来几年内启动。David,谢谢您的回答。几点澄清-我确实为NSTimer使用了ivar,我稍微简化了代码(因为在应用程序中有一些元素)。我阅读了苹果的文档,并不真正理解“NSTimer使自己失效”的概念。另外,关于我应该在我的方法中调和什么,你能说得更进一步一点吗?“int”值用于捕获NSArray中的相关对象,该方法不需要NSTimer-它需要自动触发,并且需要为下一个触发事件定义新的NSTimer。因此,当计时器向您发送消息时,SomeDatained是指向刚触发的NSTimer的指针。计时器保留“自我”,因此如果计时器处于活动状态,则无法解除锁定。每当你想准备释放当前对象时,你必须向计时器发送“invalidate”,计时器会告诉它停止并将其目标设置为nil,然后释放它。好的,我得到了invalidate问题。关于NSTimer>userInfo参数的工作方式>>那么,我应该在actionMethod中更改什么?我在一些文档中看到我应该写一些类似“-(void)actionMethod:(NSTimer*)aTimer”的东西。这就是你所说的“你需要协调它”(如果是,那么我如何收集“int somedatained”值?)的意思,还是我应该将“Target”参数从“self”更改为其他参数(如果是,更改为什么?)?如果您能澄清这一点,我将非常感谢。感谢benzado-我阅读了几篇教程,解释如何使用这些获取(NSTimer*)作为参数的方法-您的答案是我第一次真正获得它。你统治!