ios Swift 3 - 如何让计时器在后台工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42319172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:54:26  来源:igfitidea点击:

Swift 3 - How to make timer work in background

iosswifttimer

提问by Cristina Reyes

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, target: self, selector: #selector(self.scheduleNotification), userInfo: nil, repeats: true)
        RunLoop.main.add(taskManager, forMode: RunLoopMode.commonModes)

above code will perform a function that will invoke a local notification. this works when the app is in foreground, how can i make it work in the background?

上面的代码将执行一个调用本地通知的函数。这在应用程序处于前台时有效,我如何使其在后台运行?

i tried to put several print lines and i saw that when i minimize (pressed the home button) the app, the timer stops, when i go back to the app, it resumes.

我尝试放置几行打印行,我看到当我最小化(按下主页按钮)应用程序时,计时器停止,当我返回应用程序时,它会恢复。

i wanted the timer to still run in the background. is there a way to do it?

我希望计时器仍然在后台运行。有没有办法做到这一点?

here's what i want to happen:

这是我想要发生的事情:

run app -> wait 10 secs -> notification received -> wait 10 secs -> notification received -> and back to wait and received again

运行应用程序 -> 等待 10 秒 -> 收到通知 -> 等待 10 秒 -> 收到通知 -> 并返回等待并再次收到

that happens when in foreground. but not in background. pls help.

在前台时会发生这种情况。但不在后台。请帮忙。

回答by Farhad Faramarzi

you can go to Capabilities and turn on background mode and active Audio. AirPlay, and picture and picture.

您可以转到功能并打开后台模式和活动音频。AirPlay,和图片和图片。

It really works . you don't need to set DispatchQueue . you can use of Timer.

真的行 。您不需要设置 DispatchQueue 。你可以使用定时器。

Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (t) in

   print("time")
}

回答by matt

A timer can run in the background only if both the following are true:

仅当以下两项都为真时,计时器才能在后台运行:

  • Your app for some other reason runs in the background. (Most apps don't; most apps are suspended when they go into the background.) And:

  • The timer was running already when the app went intothe background.

  • 由于某些其他原因,您的应用程序在后台运行。(大多数应用程序没有;大多数应用程序在进入后台时会被暂停。)并且:

  • 当应用程序进入后台时,计时器已经在运行。

回答by Morshed Alam

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

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

回答by NIRAV BHAVSAR

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

============== 对于目标 c ================

create Global uibackground task identifier.

创建全局 uibackground 任务标识符。

UIBackgroundTaskIdentifier bgRideTimerTask;

UIBackgroundTaskIdentifier bgRideTimerTask;

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

现在创建您的计时器并添加 BGTaskIdentifier 使用它,不要忘记在创建新计时器对象时删除旧的 BGTaskIdentifier。

 [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.

在这里,即使应用程序进入后台,这也对我有用。如果您发现新问题,请询问我。

回答by cspam

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

你真的不需要跟上 NSTImer 对象。每个位置更新都有自己的时间戳。

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
                }
}

回答by Vahid

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

如果 1 或 2 秒的阈值是可以接受的,这个 hack 可能会有所帮助。

UIApplication.didEnterBackgroundNotification
UIApplication.willEnterForegroundNotification

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

停止定时器和备份Date()didEnterBackground。添加Date()到备份日期上willEnterForegraound以实现总时间。启动计时器并将总日期添加到计时器。

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

注意:如果用户更改了系统的日期时间,它将被破坏!

回答by user5855785

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

正如其他人指出的那样, Timer 不能使方法在后台运行。你可以做的是在异步任务中使用 while 循环

DispatchQueue.global(qos: .background).async {
                while (shouldCallMethod) {
                    self.callMethod()
                    sleep(1)
                }
}