代码之家  ›  专栏  ›  技术社区  ›  Michael Ninh

当应用程序在后台运行/暂停时继续倒数计时

  •  5
  • Michael Ninh  · 技术社区  · 10 年前

    我有一个功能倒计时计时器。

    问题是,当用户将应用程序置于后台时,我需要继续倒计时。还是暂停应用程序?我不确定描述这一行动的正确术语是什么。

    换句话说,用户打开应用程序并开始倒计时。用户应该可以使用其他应用程序,但倒计时仍在运行。此外,倒计时应该能够一直运行,直到它结束或用户终止运行应用程序。

    这是我计时器的代码:

        class Timer{
    var timer = NSTimer();
    // the callback to be invoked everytime the timer 'ticks'
    var handler: (Int) -> ();
    //the total duration in seconds for which the timer should run to be set by the caller
    let duration: Int;
    //the amount of time in seconds elapsed so far
    var elapsedTime: Int = 0;
    var targetController = WaitingRoomController.self
    
    var completionCallback: (() -> Void)!
    
    
    
    /**
    :param: an integer duration specifying the total time in seconds for which the timer should run repeatedly
    :param: handler is reference to a function that takes an Integer argument representing the elapsed time allowing the implementor to process elapsed time and returns void
    */
    init(duration: Int , handler : (Int) -> ()){
        self.duration = duration;
        self.handler = handler;
    }
    
    /**
    Schedule the Timer to run every 1 second and invoke a callback method specified by 'selector' in repeating mode
    */
    func start(){
        self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "onTick", userInfo: nil, repeats: true);
    }
    
    /**
    invalidate the timer
    */
    func stop(){
        println("timer was invaidated from stop()")
        timer.invalidate();
    }
    
    
    /**
    Called everytime the timer 'ticks'. Keep track of the total time elapsed and trigger the handler to notify the implementors of the current 'tick'. If the amount of time elapsed is the same as the total duration for the timer was intended to run, stop the timer.
    */
    
    
    @objc func onTick() {
        //println("onTick")
        //increment the elapsed time by 1 second
        self.elapsedTime++;
        //Notify the implementors of the updated value of elapsed time
        self.handler(elapsedTime);
        //If the amount of elapsed time in seconds is same as the total time in seconds for which this timer was intended to run, stop the timer
        if self.elapsedTime == self.duration {
            self.stop();
    
        }
    }
    deinit{
        println("timer was invalidated from deinit()")
        self.timer.invalidate();
    }
    

    }

    4 回复  |  直到 10 年前
        1
  •  10
  •   Roland Keesom    10 年前

    我建议取消计时器并存储 NSDate 当应用程序转到后台时。 您可以使用此通知检测应用程序进入后台:

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "pauseApp", name: UIApplicationDidEnterBackgroundNotification, object: nil)
    

    然后取消计时器并存储日期:

    func pauseApp(){
        self.stop() //invalidate timer
        self.currentBackgroundDate = NSDate()
    }
    

    使用此通知来检测用户返回:

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "startApp", name: UIApplicationDidBecomeActiveNotification, object: nil)
    

    然后计算存储日期与当前日期之间的差值,更新计数器并再次启动计时器:

    func startApp(){
        let difference = self.currentBackgroundDate.timeIntervalSinceDate(NSDate())
        self.handler(difference) //update difference
        self.start() //start timer
    }
    
        2
  •  4
  •   Duncan C    6 年前

    你不应该那样做。运行计时器使设备的处理器保持满功率运行,这是不好的。

    只有特定类型的应用程序才允许在后台无限期地运行代码,例如VOIP应用程序和音乐应用程序。

    两个选项:

    1. 设置未来日期的本地通知(这将向您的应用程序发送消息,或在应用程序不再运行时重新启动。)

    2. 启动计时器时,记录当前NSDate。然后,当您的应用程序返回前台或重新启动时,将当前日期与保存的日期进行比较,计算所用的时间,并确定计时器是否已完成。

        3
  •  1
  •   Manoj Reddy    9 年前

    请尝试此操作。此代码更新应用程序从后台/挂起状态返回并处于活动状态时的时间。。

    类ProgressV:UIView{

    var timer: NSTimer!
    var expirationDate = NSDate()
    
    //Set the time that you want to decrease..
    var numSeconds: NSTimeInterval = 36000.0 // Ex:10:00 hrs
    
    func startTimer()
    {
        // then set time interval to expirationDate…
        expirationDate = NSDate(timeIntervalSinceNow: numSeconds)
        timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(updateUI(_:)), userInfo: nil, repeats: true)
        NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
    
    }
    func updateUI(timer: NSTimer)
    {
      // Call the currentTimeString method which can decrease the time..
       let timeString = currentTimeString()
       labelName.text = timeString
    }
    func currentTimeString() -> String {
        let unitFlags: NSCalendarUnit = [.Hour, .Minute, .Second]
        let countdown: NSDateComponents = NSCalendar.currentCalendar().components(unitFlags, fromDate: NSDate(), toDate: expirationDate, options: [])
    
        var timeRemaining: String
        if countdown.hour > 0
        {
            timeRemaining = String(format: "%02d:%02d:%02d", countdown.hour, countdown.minute, countdown.second)
        }
        else {
            timeRemaining = String(format: "%02d:%02d:%02d", countdown.hour, countdown.minute, countdown.second)
        }
        return timeRemaining
    }
    

    }

        4
  •  1
  •   Agisight    7 年前

    确保打开后台模式并在xCode中设置所需的值。这很奇怪,但即使关闭了背景模式,这段代码也能正常工作。设置后,任何计时器似乎都在工作 application.beginBackgroundTask {} 在AppDelegate中。

    我使用以下代码:

    在AppDelegate中添加以下代码:

    func applicationDidEnterBackground(_ application: UIApplication) {
    
        application.beginBackgroundTask {} // allows to run background tasks
    }
    

    在需要的地方调用下面的方法。

    func registerBackgroundTask() {
        DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime.now() + 5, qos: .background) {
                print("fasdf")
            }
    }