Swift 3 - How to make timer work in background

后端 未结 9 411
忘掉有多难
忘掉有多难 2020-11-30 09:43

i am trying to do an application which can make a timer run in background.

here\'s my code:

let taskManager = Timer.scheduledTimer(timeInterval: 10,          


        
相关标签:
9条回答
  • 2020-11-30 10:22

    As others pointed out, Timer cannot make a method run in Background. What you can do instead is use while loop inside async task

    DispatchQueue.global(qos: .background).async {
                    while (shouldCallMethod) {
                        self.callMethod()
                        sleep(1)
                    }
    }
    
    0 讨论(0)
  • 2020-11-30 10:24

    Timer won't work in background. For background task you can check this link below...

    https://www.raywenderlich.com/143128/background-modes-tutorial-getting-started

    0 讨论(0)
  • 2020-11-30 10:24

    This works. It uses while loop inside async task, as suggested in another answer, but it is also enclosed within a background task

    func executeAfterDelay(delay: TimeInterval, completion: @escaping(()->Void)){
        backgroundTaskId = UIApplication.shared.beginBackgroundTask(
            withName: "BackgroundSound",
            expirationHandler: {[weak self] in
                if let taskId = self?.backgroundTaskId{
                    UIApplication.shared.endBackgroundTask(taskId)
                }
            })
        
        let startTime = Date()
        DispatchQueue.global(qos: .background).async {
            while Date().timeIntervalSince(startTime) < delay{
                Thread.sleep(forTimeInterval: 0.01)
            }
            DispatchQueue.main.async {[weak self] in
                completion()
                if let taskId = self?.backgroundTaskId{
                    UIApplication.shared.endBackgroundTask(taskId)
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 10:31

    If 1 or 2 seconds threshold is acceptable this hack could be helpful.

    UIApplication.didEnterBackgroundNotification
    UIApplication.willEnterForegroundNotification
    

    Stop Timer and Backup Date() on didEnterBackground. Add Date() to the Backup date on willEnterForegraound to achieve total time. Start Timer and Add total date to the Timer.

    Notice: If user changed the date time of system it will be broken!

    0 讨论(0)
  • 2020-11-30 10:33

    You dont really need to keep up with a NSTImer object. Every location update comes with its own timestamp.

    Therefore you can just keep up with the last time vs current time and every so often do a task once that threshold has been reached:

                if let location = locations.last {
                    let time = location.timestamp
    
                    guard let beginningTime = startTime else {
                        startTime = time // Saving time of first location time, so we could use it to compare later with subsequent location times.
                        return //nothing to update
                    }
    
                    let elapsed = time.timeIntervalSince(beginningTime) // Calculating time interval between first and second (previously saved) location timestamps.
    
                    if elapsed >= 5.0 { //If time interval is more than 5 seconds
                        //do something here, make an API call, whatever.
    
                        startTime = time
                    }
    }
    
    0 讨论(0)
  • 2020-11-30 10:34

    ============== For Objective c ================

    create Global uibackground task identifier.

    UIBackgroundTaskIdentifier bgRideTimerTask;

    now create your timer and add BGTaskIdentifier With it, Dont forget to remove old BGTaskIdentifier while creating new Timer Object.

     [timerForRideTime invalidate];
     timerForRideTime = nil;
    
     bgRideTimerTask = UIBackgroundTaskInvalid;
    
     UIApplication *sharedApp = [UIApplication sharedApplication];       
     bgRideTimerTask = [sharedApp beginBackgroundTaskWithExpirationHandler:^{
    
                                }];
     timerForRideTime =  [NSTimer scheduledTimerWithTimeInterval:1.0
                                                                                     target:self
                                                                                   selector:@selector(timerTicked:)
                                                                                   userInfo:nil
                                                                                    repeats:YES]; 
                                                       [[NSRunLoop currentRunLoop]addTimer:timerForRideTime forMode: UITrackingRunLoopMode];
    

    Here this will work for me even when app goes in background.ask me if you found new problems.

    0 讨论(0)
提交回复
热议问题