是否可以检测状态栏时钟“分钟”何时发生变化?

时间:2011-11-12 19:33:41

标签: iphone ios ios4

我有一个复杂的问题需要描述,所以我会保存它并总结一下我想要做的事情。当状态栏上的时间发生变化时,我希望“得到通知”,这样我就可以重新计算时间。我正在计算时间,直到很好,但是有一个1分钟的窗口,我的计算和时间戳不匹配...这一切都取决于他们何时打开应用程序,与iPhone“秒”时钟的时间相比他们打开了它。

简而言之,我们可以检测状态栏上的分钟何时发生变化吗?如果是这样,怎么样?

谢谢!

7 个答案:

答案 0 :(得分:10)

甚至比Emilio的答案更简单 - 当您的视图加载时(或当您想要触发事件时)只需检查当前日期的秒部分(例如,使用NSCalendar),安排将在60-currentSeconds中触发的计时器(将是下一分钟,零秒),最后,安排每60秒发射一次的新计时器。

答案 1 :(得分:6)

根据@ mja的建议:

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:NSSecondCalendarUnit fromDate:[NSDate date]];
NSInteger currentSecond = [components second];

//+1 to ensure we fire right after the minute change
NSDate *fireDate = [[NSDate date] dateByAddingTimeInterval:60 - currentSecond + 1];
NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate
                                          interval:60
                                            target:self
                                          selector:@selector(YOURSELECTORHERE)
                                          userInfo:nil
                                           repeats:YES];

[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

我正在使用它并且效果很好。如果您需要移除计时器,则必须更加小心。

答案 2 :(得分:2)

这就是我要做的事情:

当应用程序启动时,我会启动一个计时器,每秒更新一次,以检查时间的变化。

我第一次发现时间变化时,我会使该计时器失效并开始每分钟发射一次。

这个分钟计时器与状态栏上的时钟不会超过一秒的延迟同步。

答案 3 :(得分:2)

基于@ SG1代码示例但在Swift中:

        //calculate fireDate on every minute's first second
        let now: Date = Date()
        let calendar: Calendar = Calendar.current
        let currentSeconds: Int = calendar.component(.second, from: now)
        //init timer
        self.timer = Timer(
            fire: now.addingTimeInterval(Double(60 - currentSeconds + 1)),
            interval: 60 /*seconds*/,
            repeats: true,
            block: { (t: Timer) in
                self.sendNotification()
        })
        //start timer
        RunLoop.main.add(self.timer, forMode: RunLoopMode.defaultRunLoopMode)

        private func sendNotification(){
        ...
        }

答案 4 :(得分:0)

没有这样的通知,所以我想你需要写一些代码来经常轮询时间。我会为此创建一个运行循环源,将其添加到常用模式并让它检查当前NSTimerInterval,因为您最喜欢的参考日期大于或等于某个预先计算的NSTimeInterval包含下一整分钟的时间间隔。

答案 5 :(得分:0)

我对此进行了深入研究,找到了Calendar.nextDate(after:matching:matchingPolicy:repeatedTimePolicy:direction:)方法,完全不需要在应用程序代码中进行任何计算。

示例:

var zeroSeconds = DateComponents()
zeroSeconds.second = 0
guard let nextMinute = Calendar(identifier: .gregorian).nextDate(after: Date(), matching: zeroSeconds, matchingPolicy: .nextTime, direction: .forward) else {
  // This should not happen since there should always be a next minute
  return
}

let timer = Timer(fire: nextMinute.advanced(by: 0.1), interval: 60, repeats: true) { _ in
  // This runs at every turn of a minute
}

RunLoop.main.add(timer, forMode: .default)

正如其他答案所指出的那样,似乎需要一定的缓冲来确保在分钟过去后触发(例如,如果您要每分钟显示一次时间,则至关重要),因此nextMinute.advanced(by: 0.1)(100毫秒)。我还没有找到有关确切数量的任何文档,但是在我的简短测试中100毫秒似乎还可以。

答案 6 :(得分:0)

这是使用 scheduledTimer 触发计时器的另一种方法,该方法使用一个函数,该函数在计时器被触发后循环调用自身,而不是使用固定的 60 秒间隔。

private var timer: Timer?

private func setupTimer() {
    let calendar: Calendar = .current
    let seconds = calendar.component(.second, from: Date())
    timer = Timer.scheduledTimer(
        withTimeInterval: 60 - TimeInterval(seconds), repeats: false
    ) { [weak self] timer in
        self?.timer = nil
        // Do something, eg. update UI
        self?.setupTimer()
    }
}