NSTimer倒计时无法正常运行

时间:2017-06-30 04:25:57

标签: ios objective-c timer nstimer

我正在尝试区分时间并在ui标签中向用户显示倒数计时器

NSTimer

的声明
@property (strong, nonatomic)NSTimer *timer;

这是我的计时器在视图中加载

_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:@selector(updateCountdown:) userInfo:nil repeats: YES];

这是我的updateCountdown方法

-(void) updateCountdown:(int)secondsLeft {
    int hours, minutes, seconds;

    secondsLeft--;
    hours = secondsLeft / 3600;
    minutes = (secondsLeft % 3600) / 60;
    seconds = (secondsLeft %3600) % 60;
    _countDownlabel.text = [self timeFormatted:secondsLeft];///[NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
    NSLog(@"%@",[NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds]);
    if ( secondsLeft == 0 ) {
        [_timer invalidate];
      }
    }

我的日志详细信息是

2017-06-30 09:49:34.070 Barebones[845:56963] requestReply cust liqour category: {
date = "30-6-2017";
"end_time" = "11:41";
"market_crash" = true;
"start_time" = "09:41";
}
2017-06-30 09:49:34.070 Barebones[845:56963] true
2017-06-30 09:49:34.070 Barebones[845:56963] 09:41
2017-06-30 09:49:34.070 Barebones[845:56963] 11:41
2017-06-30 09:49:34.070 Barebones[845:56963] 30-6-2017
2017-06-30 09:49:34.073 Barebones[845:56963] 2016-12-25 08:58:00 +0000
2017-06-30 09:49:34.073 Barebones[845:56963] 2016-12-25 12:15:00 +0000
2017-06-30 09:49:34.073 Barebones[845:56963] 197.000000 is the time  difference
2017-06-30 09:49:34.073 Barebones[845:56963] 00:03:17
2017-06-30 09:49:35.075 Barebones[845:56963] 991:05:35
2017-06-30 09:49:36.075 Barebones[845:56963] 991:05:35
2017-06-30 09:49:37.075 Barebones[845:56963] 991:05:35
2017-06-30 09:49:38.075 Barebones[845:56963] 991:05:35

,此值继续执行

目标: - 倒计时直到零并停止计时器实际上我将在倒计时结束后隐藏标签

更新: -

 int secondsLeft=[self timeFormatted:[date2 timeIntervalSinceDate:date1]/60];

初始化了上面的计时器

这是我更新的计时器: -

int secondsLeft=[date2 timeIntervalSinceDate:date1]/60;

NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
                                  [NSNumber numberWithInt:secondsLeft], @"cID", nil];
_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:@selector(updateCountdown:) userInfo:userInfo repeats: YES];

这是我更新的计时器方法: -

- (void)updateCountdown:(NSTimer *)timer{
int hours, minutes, seconds;
NSDictionary *userInfo = [timer userInfo];
int secondsLeft = [[userInfo objectForKey:@"cID"] intValue];
secondsLeft--;

hours = secondsLeft / 3600;
minutes = (secondsLeft % 3600) / 60;
seconds = (secondsLeft %3600) % 60;
_countDownlabel.text = [self timeFormatted:secondsLeft];///[NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
NSLog(@"%@",[NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds]);
if ( secondsLeft == 0 ) {
    [_timer invalidate];
  }
}

3 个答案:

答案 0 :(得分:1)

您的行动方法无效。

如果传递参数,则它必须是NSTimer实例

- (void)updateCountdown:(NSTimer *)timer

要传递自定义参数,请使用userInfo参数。

然而,更合适的解决方案是使用实例变量或属性,因为userInfo的值必须是NSNumber

之类的对象

答案 1 :(得分:1)

创建属性

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCrtl">

<select ng-model="selectedItem" ng-options="item.login for item in data.items"></select>
<br>Selected Item:{{selectedItem}}
</body>
@property (nonatomic) int secondsLeft;

中的

viewDidLoad

选择器:

self.secondsLeft = 5 * 60; // 5 minutes
_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:@selector(updateCountdown) userInfo:nil repeats: YES];

答案 2 :(得分:1)

有几件事。

  1. 正如vadian所说,如果使用基于选择器的计时器,计时器处理程序函数将获取一个参数,该参数是对计时器本身的引用。如果要跟踪倒计时,可以定义属性以跟踪它:

    @interface ViewController ()
    
    @property (nonatomic, weak) IBOutlet UILabel *label;
    @property (nonatomic, weak) NSTimer *timer;
    @property (nonatomic, strong) NSDateComponentsFormatter *formatter;
    @property (nonatomic, strong) NSDate *stopTime;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.formatter = [[NSDateComponentsFormatter alloc] init];
        self.formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
        self.formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
        self.formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
    
        self.stopTime = [[NSDate date] dateByAddingTimeInterval:5 * 60];   // in 5 minutes, for example
    
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleTimer:) userInfo:nil repeats:true];
    
        [self.timer fire];    // don't wait one second before firing the first time; fire now
    }
    
    - (void)handleTimer:(NSTimer *)timer {
        NSDate *now = [NSDate date];
        if ([now compare:self.stopTime] == NSOrderedDescending) {
            // do whatever you want when timer stops
    
            [timer invalidate];
            return;
        }
    
        self.label.text = [self.formatter stringFromDate:now toDate:self.stopTime];
    }
    
    // Note, when the view disappears, invalidate the timer so the timer doesn't
    // keep strong reference to the view controller. Note that in this selector-based
    // pattern, I can't attempt to do this in `dealloc`, because the scheduled timer
    // will keep a strong reference, preventing `dealloc` from getting called. So do 
    // this in `viewDidDisappear`.
    
    - (void)viewDidDisappear:(BOOL)animated {
        [self.timer invalidate];
    }
    
    @end
    
  2. 如果仅支持iOS 10及更高版本,我建议使用完成块计时器,因为它进一步简化了过程:

    @interface ViewController ()
    
    @property (nonatomic, weak) IBOutlet UILabel *label;
    @property (nonatomic, weak) NSTimer *timer;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
        formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
        formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
        formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
    
        NSDate *stopTime = [[NSDate date] dateByAddingTimeInterval:5 * 60];  // in 5 minutes, for example
        typeof(self) __weak weakSelf = self; // make sure to not reference `self` in block below, but only reference `weakSelf` to avoid timer from maintaining strong reference
    
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:true block:^(NSTimer * _Nonnull timer) {
            NSDate *now = [NSDate date];
            if ([now compare:stopTime] == NSOrderedDescending) {
                // do whatever you want when timer stops
    
                [timer invalidate];
                return;
            }
    
            weakSelf.label.text = [formatter stringFromDate:now toDate:stopTime];
        }];
    
        [self.timer fire];    // don't wait one second before firing the first time; fire now
    }
    
    // Because I was careful to not reference `self` inside the above block, 
    // this block-based timer will NOT keep a strong reference to the view
    // controller. Nonetheless, when the view controller is dismissed, I want
    // to stop the timer, to avoid wasting CPU cycles on a timer that isn't
    // needed anymore.
    
    - (void)dealloc {
        [self.timer invalidate];
    }
    
    @end
    

    显然,如果您还需要支持iOS 9及更早版本,那么您必须使用上述基于选择器的解决方案。

  3. 我建议不要依赖计时器来调整时间,因为您不能确保以您想要的频率调用计时器。在上面的两个例子中,我捕捉到我倒计时的时间,并且只显示&#34;现在&#34;之间的时间量。那个预定的&#34;停止时间&#34;。

  4. 请注意,我还建议你不要自己构建格式字符串。这是一个方便的NSDateComponentsFormatter,可以为您格式化。如果可以,请使用它。

  5. 您制作了计时器参考strong。您可以将其设为weak,因为计划的计时器在invalidated之前不会被取消分配。一旦它invalidated,就可以自动为您解除分配。