2014-09-04 86 views
4

嘿,我正在开发一个应用程序,我必须每30秒进行一次API调用,所以我为它创建了NSTimer。 但是当我的应用程序进入后台计时器3-4分钟后停止发射。所以它只能在后台运行3-4分钟,但在此之后才能运行。我如何修改我的代码,以便计时器不会停止。NSTimer在一段时间后在后台停止射击

这是我的一些代码。

- (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]; 

这也不能工作。

+2

不使用背景模式中的一种,你会在后台完成的任务(iOS上的7 3分钟)只得到3分钟,见这里:https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html,哪种背景模式适合您的情况 – 2014-09-04 06:00:14

回答

2

不,不要用NSTimer做后台任务。它不会像你所期望的那样工作。您应该只使用Apple提供的后台提取API。您可以设置您希望在该API中调用的持续时间。虽然通常不建议设置您想要的通话时长。看看这个apple background programming documentation

而且,让你快速入门,你可以按照这个Appcoda tutorial

7

不要创建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:^ {endBackgroundTask:bgTask]; //删除这行,只要计时器正在运行并且应用程序被杀死,它就会运行,然后自动转储所有的实例和范围。 }];

检查它,让我知道它是否工作或没有。

嘿我运行你的代码,我到达expirationHandler但释放调试点后,计时器运行平稳。

Highlighted part is when I reached handler

+0

谢谢Nikhil, 我试着按照您的解决方案,但它不起作用。 我的计时器在3分钟后再次停止。 – 2014-09-04 06:32:31

+0

@VivekShah我已编辑我的帖子请看看。 – nikhil84 2014-09-04 06:44:30

+0

是Nikhil, 如果我连接了我的设备,然后运行应用程序,然后去背景我的NSLog行正在执行没有任何问题。 我维护项目中的日志文件。因此,从“LOG调试”我知道,当我的设备没有连接和应用程序在后台,它只能运行3分钟。 如果你想检查完整的源代码然后让我知道。 – 2014-09-04 06:54:54

2

这是正常行为。

iOS7之后,你恰好有3分钟的背景时间。在那之前,如果我没有记错,那就有10分钟了。为了扩展这一点,你的应用程序需要使用一些特殊的服务,如位置,音频或蓝牙,这将在后台保持“活跃”。

此外,即使您使用这些服务之一,必须在设备上为应用程序启用“后台应用程序刷新”设置。

请参阅this回答详情或文档背景执行部分。

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包含“所需的背景模式”,并且“应用程序使用AirPlay播放音频或流式传输音频/视频“又名‘声音’是在其收集):

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分钟(只需用例如AudaCity创建一个“Silent.mp3”,然后将其拖放到您的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 { } 
     } 
    } 
} 
+0

Downvoted,因为这几乎肯定会让您的应用程序从应用程序商店被拒绝。 – 2017-04-25 10:13:18