【问题标题】:Is it possible to detect when the "Minute" changes on the status bar clock?是否可以检测状态栏时钟上的“分钟”何时更改?
【发布时间】:2011-11-12 19:33:41
【问题描述】:

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

简而言之,我们可以检测状态栏上的分钟变化时间吗?如果有,怎么做?

谢谢!

【问题讨论】:

    标签: iphone ios ios4


    【解决方案1】:

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

    【讨论】:

    • 这是最聪明的答案。
    • 这对我有用,但我必须做 61-currentSeconds
    【解决方案2】:

    根据@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];
    

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

    【讨论】:

      【解决方案3】:

      基于@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】:

        我对此进行了深入研究,发现了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 毫秒似乎还可以。

        【讨论】:

        • 这对我来说非常适合,你在哪里找到的文档?因为我不明白这是如何工作的
        • 在我看来,这是最准确的答案。干得好?
        • @FarrasDoko 它的工作原理是创建一个 Date 对象,表示下一分钟的更改(即,秒数 == 0 的下一个日期)。然后它创建一个计时器来触发Date(好吧,加上 0.1 秒以确保在分钟之交正确调用此方法的情况下不会错过它),然后每 60 秒触发一次。
        【解决方案5】:

        这就是我要做的:

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

        当我第一次发现时间变化时,我会让那个计时器失效并启动一个每分钟触发一次的计时器。

        此分钟计时器将与状态栏上的时钟同步,延迟不超过一秒。

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            这是使用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()
                }
            }
            

            【讨论】:

              【解决方案8】:

              基于@stefanlindbohm 的回答,但没有强烈引用self,如果对象已被释放,则在下次触发时停止计时器:

              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
              }
              
              var timer: Timer?
              timer = Timer(fire: nextMinute.advanced(by: 0.1), interval: 60, repeats: true) { [weak self] _ in
                  guard let self = self else {
                      timer?.invalidate()
                      timer = nil
                      return
                  }
              
                  // Do your work here, using `self`.
              }
              
              if let timer = timer {
                  RunLoop.main.add(timer, forMode: .default)
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2019-11-10
                • 2019-05-28
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多