一段时间后,NSTimer在后台停止射击

时间:2014-09-04 05:45:10

标签: ios timer nstimer

嘿我正在开发一个应用程序,我必须每隔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];

这也不起作用。

4 个答案:

答案 0 :(得分:8)

不要将UIBackgroundTaskIdentifier任务创建为本地任务,并将其设为全局,如下所示:

步骤-1

Initiating varible

步骤-2

ViewDidLoad Method and added barButton

第3步

BarButton method call

步骤-4

Timer method call

由于本地一个松散的范围和全局的一个不会,我创建了一个演示并运行它一段时间,1秒重复计时器,并顺利工作。 如果你面临问题,请告诉我。

我又跑了一下demo,这里有运行的日志。 enter image description here

所以它的工作正常,超过3分钟。另外3分钟的逻辑是正确的,但是当启动uibackgroundtask时它不应该让它杀死这个计时器任务。

编辑部分: - bgTask = [app beginBackgroundTaskWithExpirationHandler:^ {         [app endBackgroundTask:bgTask]; //删除此行,只要计时器正在运行,它就会运行,当应用程序被终止时,它会自动转储它的所有vairbles和范围。     }];

检查并告知我是否有效。

嘿,我运行了你的代码,我到达了expirationHandler,但是在发布调试点后,计时器运行顺畅。

Highlighted part is when I reached handler

答案 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 { }
        }
    }
}