NSTimer每分钟运行一次但是在第一秒运行

时间:2014-12-01 15:54:59

标签: ios objective-c swift

我有使用NSTimer的经验,每分钟运行一次,如

NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: Selector("everyMinute"), userInfo: nil, repeats: true)

是否可以使用NSTimer,其他一些类或其他控件,每分钟运行一些方法,但是在第一分钟?

我确实知道如何自己实现它,但我首先检查这是否已存在?

4 个答案:

答案 0 :(得分:8)

一种方法是使用NSCalendar计算当前的下一分钟并安排计时器从那里开始,在runLoop上手动调度

let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(NSCalendarUnit.CalendarUnitEra|NSCalendarUnit.CalendarUnitYear|NSCalendarUnit.CalendarUnitMonth|NSCalendarUnit.CalendarUnitDay|NSCalendarUnit.CalendarUnitHour|NSCalendarUnit.CalendarUnitMinute, fromDate: date)
components.minute += 1
components.second = 1
let nextMinuteDate = calendar.dateFromComponents(components)
let timer = NSTimer(fireDate: nextMinuteDate!, interval: 60, target: self, selector: Selector("everyMinute"), userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)

答案 1 :(得分:2)

accepted answer,针对Swift 4进行了更新:

let date = Date()
let calendar = Calendar.current
var components = calendar.dateComponents([.era, .year, .month, .day, .hour, .minute], from: date)

guard let minute = components.minute else { return }
components.second = 0
components.minute = minute + 1

guard let nextMinute = calendar.date(from: components) else { return }

let timer = Timer(fire: nextMinute, interval: 60, repeats: true) { [weak self] timer in
    self?.everyMinute()
}
RunLoop.main.add(timer, forMode: .defaultRunLoopMode)

答案 2 :(得分:1)

NSDate方法timeIntervalSinceReferenceDate返回自2001年1月1日格林尼治标准时间上午12:00起的秒数。它包括一小部分

如果你打电话给它,除以60,取楼层值,然后乘以60,它应该给你当前“圆分钟”的时间间隔。添加60,你得到下一个“圆分钟”的时间间隔。加1到那个,你在下一个“圆分钟”后得到一秒的时间间隔。

代码可能如下所示:

NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval nextMinute = floor(now/60)*60 + 61 //time interval for next minute, plus 1 second
NSTimeInterval delay = nextMinute - now;
//Delay now contains the number of seconds until the next "round minute", plus 1 second.

dispatch_after(
  dispatch_time(DISPATCH_TIME_NOW, 
  (int64_t)(delay * NSEC_PER_SEC)), 
  dispatch_get_main_queue(), ^
  {
    //Replace the code below with whatever target/userInfo you need.
    [NSTimer scheduledTimerWithTimeInterval: 60
      target: self
      userInfo: nil;
      repeats: YES];
  }
);

编辑:实际上,一分钟的“第一秒”是第零秒,所以您应该将计算出的nextMinute上面的代码中的+61更改为“+60”,而不是“+” 61"

答案 3 :(得分:0)

更简单的方法:

func everyMinute() {
  // some code you want done every minute, in the first second, or VERY close to it
  let delaySeconds = 60 - NSDate.timeIntervalSinceReferenceDate.truncatingRemainder(dividingBy: 60)
  Timer.scheduledTimer(withTimeInterval: delaySeconds, repeats: false) { timer in 
     self.everyMinute()
  }
}