嘿我正在开发一个应用程序,我必须每隔30秒进行一次API调用,所以我为它创建了NSTimer。 但当我的应用程序进入后台计时器后3-4分钟停止发射。因此它在后台只能工作3-4分钟,但之后却没有。如何修改我的代码,以便计时器不会停止。
以下是我的一些代码。
- (IBAction)didTapStart:(id)sender {
NSLog(@"hey i m in the timer ..%@",[NSDate date]);
[objTimer invalidate];
objTimer=nil;
UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
objTimer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self
selector:@selector(methodFromTimer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:objTimer forMode:UITrackingRunLoopMode];
}
-(void)methodFromTimer{
[LOG debug:@"ViewController.m ::methodFromTimer " Message:[NSString stringWithFormat:@"hey i m from timer ....%@",[NSDate date] ]];
NSLog(@"hey i m from timer ....%@",[NSDate date]);
}
我甚至用以下内容更改了代码:
[[NSRunLoop mainRunLoop] addTimer:objTimer forMode:NSRunLoopCommonModes];
这也不起作用。
答案 0 :(得分:8)
不要将UIBackgroundTaskIdentifier任务创建为本地任务,并将其设为全局,如下所示:
步骤-1
步骤-2
第3步
步骤-4
由于本地一个松散的范围和全局的一个不会,我创建了一个演示并运行它一段时间,1秒重复计时器,并顺利工作。 如果你面临问题,请告诉我。
我又跑了一下demo,这里有运行的日志。
所以它的工作正常,超过3分钟。另外3分钟的逻辑是正确的,但是当启动uibackgroundtask时它不应该让它杀死这个计时器任务。
编辑部分: - bgTask = [app beginBackgroundTaskWithExpirationHandler:^ { [app endBackgroundTask:bgTask]; //删除此行,只要计时器正在运行,它就会运行,当应用程序被终止时,它会自动转储它的所有vairbles和范围。 }];
检查并告知我是否有效。
嘿,我运行了你的代码,我到达了expirationHandler,但是在发布调试点后,计时器运行顺畅。
答案 1 :(得分:2)
不,不要使用NSTimer执行后台任务。它不会像你期望的那样工作。您应该只使用Apple提供的后台提取API。您可以设置在该API中调用它的持续时间。虽然通常不建议您设置您想要的通话时间。看一下这个apple background programming documentation
另外,为了让您快速入门,您可以按照此Appcoda tutorial
进行操作答案 2 :(得分:2)
这是正常行为。
在iOS7之后,你有3分钟的背景时间。如果我没记错的话,在那之前有10分钟。为了扩展它,你的应用程序需要使用一些特殊的服务,如位置,音频或蓝牙,这将使它保持活着"在后台。
此外,即使您使用其中一项服务,"后台应用刷新"必须在您的设备上为该应用启用该设置。
有关详细信息或文档的后台执行部分,请参阅this答案。
答案 3 :(得分:2)
这对我有用,所以我将它添加到StackOverflow以供将来的任何求职者使用。
在启动计时器之前添加以下要调用的实用程序方法。当我们调用AppDelegate.RestartBackgroundTimer()时,它将确保您的应用程序保持活动状态 - 即使它在后台或屏幕被锁定。但是,这只会确保3分钟(如您所述):
class AppDelegate: UIResponder, UIApplicationDelegate {
static var backgroundTaskIdentifier: UIBackgroundTaskIdentifier? = nil;
static func RestartBackgroundTimer() {
if (AppDelegate.backgroundTaskIdentifier != nil) {
print("RestartBackgroundTimer: Ended existing background task");
UIApplication.sharedApplication().endBackgroundTask(AppDelegate.backgroundTaskIdentifier!);
AppDelegate.backgroundTaskIdentifier = nil;
}
print("RestartBackgroundTimer: Started new background task");
AppDelegate.backgroundTaskIdentifier = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
UIApplication.sharedApplication().endBackgroundTask(AppDelegate.backgroundTaskIdentifier!);
AppDelegate.backgroundTaskIdentifier = nil;
})
}
}
此外,启动应用时,请确保以下运行。它将确保即使应用程序处于后台也能播放音频(当您使用它时,还要确保您的Info.plist包含“所需的背景模式”,以及“App使用AirPlay播放音频或流音频/视频“aka”audio“在其收藏中):
import AVFoundation;
// setup audio to not stop in background or when silent
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback);
try AVAudioSession.sharedInstance().setActive(true);
} catch { }
现在,在需要定时器运行超过3分钟(如果在后台)的类中,您需要在仅剩30秒的背景时间时播放声音。这会将剩余的背景时间重置为3分钟(只需创建一个“Silent.mp3”,例如AudaCity,然后将其拖放到您的XCode项目中)。
要完成所有操作,请执行以下操作:
import AVFoundation
class MyViewController : UIViewController {
var timer : NSTimer!;
override func viewDidLoad() {
// ensure we get background time & start timer
AppDelegate.RestartBackgroundTimer();
self.timer = NSTimer.scheduledTimerWithTimeInterval(0.25, target: self, selector: #selector(MyViewController.timerInterval), userInfo: nil, repeats: true);
}
func timerInterval() {
var bgTimeRemaining = UIApplication.sharedApplication().backgroundTimeRemaining;
print("Timer... " + NSDateComponentsFormatter().stringFromTimeInterval(bgTimeRemaining)!);
if NSInteger(bgTimeRemaining) < 30 {
// 30 seconds of background time remaining, play silent sound!
do {
var audioPlayer = try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Silent", ofType: "mp3")!));
audioPlayer.prepareToPlay();
audioPlayer.play();
} catch { }
}
}
}