【问题标题】:NSTimer doesn't stopNSTimer 不会停止
【发布时间】:2010-11-05 02:48:53
【问题描述】:

我有一个计时器,它在调用viewWillAppear 方法时触发,并在调用viewDidDisappear 方法时失效。但是在视图之间进行了一定量的切换后,即使在它失效后,定时器也会继续触发。有什么问题?

这是我的代码:

NSTimer *timer;

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    timer = [NSTimer scheduledTimerWithTimeInterval: 0.2f
                     target: self
                     selector:@selector( timerAction )
                     userInfo:nil
                     repeats:YES];
}

-(void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [timer invalidate];
    timer = nil;
}

-(void) timerAction
{
    NSLog(@"timerAction");
}

【问题讨论】:

    标签: iphone cocoa-touch timer


    【解决方案1】:

    这在 Swift 中对我有用

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
    
        dispatch_async(dispatch_get_main_queue(),{ [weak self] in
    
            self?.idleTimer?.invalidate()
            self?.idleTimer = nil
    
        })
    
    }
    

    【讨论】:

      【解决方案2】:

      这对我有用

      dispatch_async(dispatch_get_main_queue(), ^{
          [timer invalidate];
      });
      

      【讨论】:

        【解决方案3】:

        创建计时器后,只需注册它以在NSRunLoopCommonModes 中运行:

        [[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];

        然后invalidate 方法将起作用。

        【讨论】:

          【解决方案4】:

          - (void)viewWillAppear:(BOOL)animated 再次被调用。

          事实上,每次切换视图或关闭模式视图时都会调用它。基本上任何时候您的视图实际上都会重新出现在屏幕上,而不仅仅是第一次。

          所以在这种情况下,计时器会重新启动,即使之前已失效。

          【讨论】:

            【解决方案5】:

            这是一个绝对的解决方案。以上这些都不适合我,所以我这样做了,

            你想在哪里开始计时器,

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

            定时器调用的方法,

            -(void)timerMethod
            {
                // do what you need to do
            
                if (needs to be called again) {
            
                    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:NO];        
                }
            }
            

            希望这会有所帮助,

            【讨论】:

            • 确实...对我来说这看起来像是 Apple 的错误。由于将重复 BOOL 值设置为 YES,invalidate 方法不起作用,这对我来说有点奇怪
            • 这个bug在iOS8中依然存在。这是解决问题的唯一方法。
            【解决方案6】:
            **In .h class**
            
            @interface 
            {
            NSTimer * theTimer;
            
            }
            
            
            **in .m class**
            
            //put this code where you want to calling the NSTimer function
            
                    theTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateCounter:) userInfo:nil repeats:YES];
            
            
            
            - (void)updateCounter:(NSTimer *)theTimer 
            {
            
               // write your code here for counter update 
            
            }
            
            
            // put this code to Stop timer:
            
                [theTimer invalidate];
                theTimer = nil;
            

            【讨论】:

              【解决方案7】:

              我遇到了同样的问题。

              如果计时器仍在运行,我无法释放我的实例,因此我必须在调用之前停止它:

              - (void)stopTimer
              {
                  [timer invalidate];
                  [timer release];
                  timer = nil;
              }
              

              调用此方法后,我的计时器真的停止了

              【讨论】:

                【解决方案8】:

                我应该通过保留它来保持与计时器的链接。 :) 我在 5 个月前问过这个问题,令人惊讶的是,我获得了多少经验。 :)

                timer = [ [NSTimer scheduledTimerWithTimeInterval: ...] retain];
                ...
                ...
                [timer invalidate];
                [timer release];
                

                【讨论】:

                • retainrelease 不被允许时如何在ARC 中执行此操作?
                • 对于 iOS 7/8,请参阅下面关于使用一对 repeats: NO 计时器的答案。
                【解决方案9】:

                这可能不是问题,但您需要保留对从 scheduleTimerWithInterval: 返回的计时器的引用。如果不这样做,您指向计时器的指针可能会在您停止它时无效。

                - (void)viewWillAppear:(BOOL)animated
                {
                    [super viewWillAppear:animated];
                    timer = [[NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:@selector(timerAction) userInfo:nil repeats:YES] retain];
                }
                
                - (void)viewDidDisappear:(BOOL)animated
                {
                    [timer invalidate];
                    [timer release];
                    timer = nil;
                    [super viewDidDisappear:animated];
                }
                
                - (void)dealloc
                {
                    [timer invalidate];
                    [timer release];
                    timer = nil;
                    [super dealloc];
                }
                

                另外,尝试在 viewDidDisappear 中设置断点并确保它被调用!

                【讨论】:

                  【解决方案10】:

                  定时器调用的方法应该有定义

                  - (void)methodName:(NSTimer *)aTimer;
                  

                  这样,该方法就有了被触发的计时器实例。您这样做的方式,该方法将不知道计时器是否无效。

                  尝试将您的计时器初始化更改为

                  timer = [NSTimer scheduledTimerWithTimeInterval: 0.2f target: self selector:@selector(timerAction:) userInfo:nil repeats:YES]
                  

                  和方法

                  -(void) timerAction:(NSTimer *)aTimer{...}
                  

                  希望有帮助

                  【讨论】:

                  • 这实际上不会有任何效果。
                  • @rpetrich 如果您可以在回复中提供更少的信息,那就太好了!
                  • 使方法中的计时器对象无效,并使其为零。还要确保将 NSTimer 声明为保留属性。这对我有用。
                  【解决方案11】:

                  invalidatedoco

                  “运行循环会在 invalidate 方法返回之前或稍后的某个时间点移除并释放计时器。”

                  我想你的会在稍后被删除。

                  【讨论】:

                    【解决方案12】:

                    你忘记释放viewWillDisappear:中的定时器

                    - (void)viewDidDisappear:(BOOL)animated
                    {
                        [super viewDidDisappear:animated];
                        [timer invalidate];
                        [timer release];
                        timer = nil;
                    }
                    

                    这不应该导致计时器继续触发...

                    【讨论】:

                    • 在这种情况下,应用程序崩溃了,因为计时器已经被释放了。
                    • Ben Gotow 在这里给出了正确的答案。您必须在创建计时器后保留它,然后在您希望它停止呼叫您时使其无效并释放它
                    • 你不需要 /have/ 来保留它,因为运行循环会这样做,但如果你想安全的话,这是个好主意。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-01-30
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-12-08
                    • 2011-03-31
                    • 1970-01-01
                    相关资源
                    最近更新 更多