【问题标题】:NSTimer Not Stopping When InvalidatedNSTimer 无效时不停止
【发布时间】:2013-05-10 05:21:44
【问题描述】:

我的 .h 文件中有以下代码:

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <AVFoundation/AVFoundation.h>
#import <MapKit/MapKit.h>

@interface LandingController : UIViewController<CLLocationManagerDelegate> {
    CLLocationManager *LocationManager;
    AVAudioPlayer *audioPlayer;

}

@property (nonatomic, retain) NSTimer *messageTimer;

- (IBAction)LoginButton:(id)sender;

@end

我的 .m 文件中有以下代码:

@interface LandingController ()

@end

@implementation LandingController
@synthesize messageTimer;

- (void)checkForMessages
{

    UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@"BINGO:"
                          message:@"Bingo This Works"
                          delegate:nil
                          cancelButtonTitle:@"Okay"
                          otherButtonTitles:nil];

    [alert show];

}

- (IBAction)LoginButton:(id)sender {

    if ([UserType isEqualToString:@"Owner"]) {

        if (messageTimer){ 
        [self.messageTimer invalidate];
        self.messageTimer = nil;
        }

    } else {

        if (!messageTimer){

           self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
                                                             target:self
                                    selector:@selector(checkForMessages)
                                                           userInfo:nil
                                                            repeats:YES];


        }
    }

}

@end

但是当我调用无效时,我的计时器不想停止。

LoginButton 只被按下了两次,一次当 strResult 为 =“Guard”,然后应用程序将其更改为等于“Owner”并且用户再次按下登录按钮,所以我不认为我' m 设置多个定时器。

在按下登录按钮并启动计时器后,我切换到另一个视图,然后再次切换到再次按下登录按钮,此时我希望计时器停止。我是否需要做任何特别的事情来获取 messageTimer ,因为我切换了一会儿视图然后又回来了?

有什么想法吗?

谢谢!

【问题讨论】:

  • 你在哪里写了 scheduleTimerWithTimeInterval 代码?检查一下,即使您将其无效,它也必须再次初始化。
  • 我把它写在一个 if 循环中,这个循环在应用程序中只发生一次,所以我认为它不会被重新初始化。
  • 我添加了更多代码 - 见上文
  • 能否在将 self.messageTimer 设置为 nil 之前检查 [self.messageTimer isValid] 的值是否为 NO?
  • 刚刚添加了更多代码,类似的东西?

标签: objective-c nstimer


【解决方案1】:

您需要在创建计时器的同一线程上调用[self.messageTimer invalidate]。只需确保在主线程上创建了计时器并使其失效。

dispatch_async(dispatch_get_main_queue(), ^{
    if ([UserType isEqualToString:@"Owner"]) {
        [self.messageTimer invalidate];
        self.messageTimer = nil;
    } else {
        self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
                                                             target:self
                                                           selector:@selector(checkForMessages)
                                                           userInfo:nil
                                                            repeats:YES];
    }
});

【讨论】:

  • 如果我在 ELSE 中调用一个,在 IF 中调用另一个,它们不会在同一个主线程上吗?
  • 当用户按下按钮并启动时,会触发此 IF/ELSE 情况 (IBAction)LoginButton:(id)sender { //if else statement here }
  • 在主线程中创建和使我的音频记录计划计时器无效并不会改变计时器永远不会结束的事实。这个问题让我抓狂。
【解决方案2】:

NSTimer 由 NSRunLoop 保留,所以我看到您的问题发生的唯一方法是,如果您实际上创建了多个计时器并且仅使您引用的内容无效。

例子:

if(!timer)
        timer = [NSTimer scheduledTimerWithTimeInterval:1 target:(self) selector:@selector(processTimer) userInfo:nil repeats:YES];

【讨论】:

  • 我把它写在一个 if 循环中,它只在应用程序中发生一次,所以我认为它不会被重新初始化。还有其他想法吗?!
  • 我已经用 IF 循环更新了代码。页面加载时的第一个状态不是 OWNER,然后切换到 OWNER 应该触发停止计时器。我知道它正确地命中了 if 语句,因为我在两个部分中都放置了警报以进行验证。唯一的问题是计时器不会停止。
  • 你说得对,我调用了一个方法两次,那就是初始化 NSTimer。 (即在ViewDidLoadViewWillAppear 中)。谢谢!
  • @DmitryShevchenko 非常感谢。现在我将把它作为标准做法。
【解决方案3】:

您是否尝试将重复设置为否

self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
                                                             target:self
                                                          selector:@selector(checkForMessages)
                                                           userInfo:nil
                                                            repeats:NO];

【讨论】:

  • 但是如果我希望它每 10 秒运行一次计时器,我不需要将重复设置为 YES 吗?
  • 看起来如果我将它设置为 NO 它只运行一次计时器,但我肯定需要它连续运行直到我告诉它停止。
  • 好的,那么 if ([UserType isEqualToString:@"Owner"]){} 从哪里调用它?这是在同一个类实例中还是在任何其他实例中?
  • 两者在同一个实例 .m 文件中。
  • 所以有些地方你必须在尝试停止这个计时器之前更新 userType 对吗?如果是这样,您是如何更新 userType 的?
【解决方案4】:

如果最后的代码(以 if 开头)以 UserType != Owner 调用两次,则您可以创建一个新的计时器,而不会使旧的计时器失效。现在有两个计时器正在运行。如果代码第三次执行,您将添加第三个计时器,依此类推。使用 UserType == Owner 执行代码只会使最后一个计时器失效,即使它被重复调用,也不会使旧的计时器失效。

你有一个计时器泄漏。 ;-)

【讨论】:

  • 我希望它是一个泄漏!我在日志和警报中都添加了以验证只有一个计时器在运行,并且我确定只有一个计时器在运行。计时器启动警报仅发生一次,计时器停止警报仅发生一次,但计时器继续运行。还有其他想法吗?
  • 我不明白,你想用你的评论说什么。然而,一个计时器继续运行,即使NSTimer 的实例被释放。你必须发送-invalidate
【解决方案5】:

在你的checkForMessages 方法中加入一个NSLog 怎么样?检查是否真的只有1个计时器会更容易。

(我宁愿把它放在评论中,但我没有那么大的声誉......)

【讨论】:

  • 我在日志和警报中都添加了以验证只有一个计时器在运行,并且我确定只有一个计时器在运行。计时器启动警报仅发生一次,计时器停止警报仅发生一次,但计时器继续运行。
【解决方案6】:

我有一种停止或停用计时器的方法,在应用此方法之前,请确保您尝试了上述所有情况,这样您也可以理解为什么最后使用了这种方法。

 // Instead of self use NSTimer class, it will not provide you any crash and in selector placed any empty function and setRepeats to NO

self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:100.0
                       target:NSTimer selector:@selector(emptyFunctionCalling)
                                                                   userInfo:nil
                                                                    repeats:NO];
[self.messageTimer invalidate];
 self.messageTimer = nil;

因此,无论何时发生计时器不会停止的情况,然后输入此代码,计时器将永久停止。

【讨论】:

    【解决方案7】:

    它奇怪但无效的传递计时器引用和创建的计时器引用对我有用。

        delayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateDelayLable:) userInfo:nil repeats:YES];
    
        -(void)updateSendDataDelayLable:(NSTimer*)timer{
    delayValueForGNSS--;
    
                    if (delayValueForGNSSSend==0) {
                         [timer invalidate];
                         timer = nil;
                         [delayTimer invalidate];
                         delayTimer = nil;
                    }
                }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 2013-01-30
      • 1970-01-01
      相关资源
      最近更新 更多