Ios 当触发时间可能发生变化时,如何使用要触发的自动计划动作?

Ios 当触发时间可能发生变化时,如何使用要触发的自动计划动作?,ios,nstimer,nstimeinterval,Ios,Nstimer,Nstimeinterval,在某个视图中,我希望在触发时间基于NSTimeInterval数组时触发某个方法(我将其作为NSArray保留双值) 因此,我有一个方法,它根据相关的时间执行相关的操作,在这个方法中,我(递归地)调用相同的方法,以便在下一个计划的时间再次触发: -(void) actionMethod:(int)someDataINeed { //do something and then... if (someDataINeed == someDefinitionIHaveToBreakT

在某个视图中,我希望在触发时间基于NSTimeInterval数组时触发某个方法(我将其作为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];
}
嗯。。。它不起作用(如果有,我想我不会问它……)。 当我记录它时,似乎时间根本没有运行,计时器在某种循环中被调用,并且没有根据我定义的时间“被触发”。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]

  • 如果您可以确保目标始终存在,并且接收消息总是可以的,那么您不需要做任何事情。例如,应用程序委托对象将在应用程序的生命周期内存在

    NSTimer的目标行动 不能将计时器设置为仅调用任何对象上的任何方法。timer方法只能接受一个参数,即发送消息的NSTimer实例。您已经定义了
    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*)作为参数的方法-您的答案是我第一次真正获得它。你统治!