ios - 只保留一项后台任务

标签 ios uibackgroundtask

我正在开发一个应用程序,该应用程序使用后台任务每 20 秒跟踪一次用户位置。一切都很好,除了当我在后台进入应用程序时,会创建一个新的后台任务,这样我就可以在最终运行多个后台任务。 我尝试在 applicationWillEnterForeground 中添加 [[UIApplication sharedApplication] endBackgroundTask:bgTask]; ,但这没有任何作用。 重点是,我想在进入应用程序时使所有正在运行的后台任务无效/禁用,并在进入后台时创建一个新任务,或者仅保持一个后台任务运行。

- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self runBackgroundTask:10];
}

-(void)runBackgroundTask: (int) time{
    //check if application is in background mode
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {

        __block UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
            [[UIApplication sharedApplication] endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }];

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(startTracking) userInfo:nil repeats:NO];
            [[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
            [[NSRunLoop currentRunLoop] run];
        });
    }
}

-(void)startTracking{
//Location manager code that is running well
}

最佳答案

我建议将 UIBackgroundTaskIdentifier 更改为应用委托(delegate)类的属性,并在 didFinishLaunchingWithOptions 中将其初始化为 UIBackgroundTaskInvalid。然后,在您的其他应用程序委托(delegate)方法中,您只需检查此属性的值即可确定是否有要结束的后台任务标识符。

--

一个不相关的观察结果,但你不需要运行循环的东西。只需在主线程/运行循环上安排计时器(使用 scheduledTimerWithTimeInterval)并摆脱所有运行循环内容(因为您已经将其添加到主运行循环并且该运行循环已经在运行)。

例如,假设我想在应用程序处于后台时每 10 秒执行一次操作,我会执行如下操作:

@interface AppDelegate ()

@property (atomic) UIBackgroundTaskIdentifier bgTask;
@property (nonatomic, weak) NSTimer *timer;

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.bgTask = UIBackgroundTaskInvalid;
    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        if (self.bgTask != UIBackgroundTaskInvalid) {
            [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
            self.bgTask = UIBackgroundTaskInvalid;
        }
    }];

    self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(startTracking) userInfo:nil repeats:YES];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // invalidate the timer if still running

    [self.timer invalidate];

    // end the background task if still present

    if (self.bgTask != UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
        self.bgTask = UIBackgroundTaskInvalid;
    }
}

- (void)startTracking{
    NSLog(@"%s", __PRETTY_FUNCTION__);
}

现在,在您的代码示例中,计时器不是重复计时器,因此如果您只想触发计时器一次,请将 repeats 设置为 NO,但随后请确保 startTracking 结束了后台任务(如果您不打算执行任何其他操作,则保持应用程序处于事件状态是没有意义的)。

顺便说一句,请确保您在设备上运行此代码,并且不要从 Xcode 运行它(因为附加到 Xcode 会更改应用程序的后台行为)。

关于ios - 只保留一项后台任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33786515/

相关文章:

ios - 应用目标名称中的非 ASCII 字符

ios - 为什么在某些情况下 View 的快照看起来会大两倍?

ios - 应用程序因 AVAudioSession privateBeginInterruption 而崩溃

如果在手机锁定(屏幕关闭)时启动,iOS 后台任务不会保持事件状态

ios - 通过静默推送通知启动 LocationManager 的 startUpdatingLocation

ios - Swift 2.0 Call Can Throw 但没有标上try

ios - 从解析崩溃报告中获取行号

ios - 当应用程序处于后台或终止(终止)状态时,在 iOS 应用程序中执行任务

iOS13不支持后台更新通知吗?