服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS应用进入后台后计时器和位置更新停止问题的解决办法

iOS应用进入后台后计时器和位置更新停止问题的解决办法

2021-03-08 15:15chips_柯 IOS

这篇文章主要介绍了iOS应用进入后台后计时器和位置更新停止问题的解决办法,非常不错,具有参考借鉴价值,需要的朋友可以参考下

由于iOS系统为“伪后台”运行模式,当按下HOME键时,如程序不做任何操作,应用会有5秒的执行缓冲时间,随机程序被挂起,所有任务终端,包括计时器位置更新等操作,但程序打开后台模式开关后,部分任务可以再后台执行,如音频,定位,蓝牙,下载,VOIP,即便如此,程序的后台运行最多可以延长594秒(大概是10分钟)。不幸的是,程序在声明后台模式后很有可能在app上架时被拒。基于此,我研究出了不用申明后台模式就能让计时器和定位在app进入前台时继续运行的方法。

  实现原理如下:

  利用iOS的通知机制,在程序进入后台和再次回到前台时发送通知,并记录进入后台的当前时间和再次回到前台的当前时间,算出两者的时间间隔,在程序任何需要的地方添加通知监听者,在监听方法中执行代码块,代码块内参数为通知对象和计算出的时间间隔。以计时器为例,程序再进入后台后,计时器停止运行,此时运用上述方法,在程序再次回到前台时执行代码块中内容,将程序进入后台时计时器的当前时间间隔加上代码块的时间间隔参数就能使计时器准确无误地计时。废话不多说,上代码:

在AppDelegate.m实现文件中:

?
1
2
3
4
5
6
7
8
9
- (void)applicationDidEnterBackground:(UIApplication *)application {
  // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
  // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
  [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
  // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
  [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationWillEnterForegroundNotification object:nil];
}

代码说明:程序进入后台后,利用系统通知机制通知程序进入后台和再次回到前台,监听对象为所有对象。

之后定义一个处理程序进入后台的类YTHandlerEnterBackground

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
// YTHandlerEnterBackground.h
// 分时租赁
//
// Created by 柯其谱 on 17/2/24.
// Copyright © 2017年 柯其谱. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
/** 进入后台block typedef */
typedef void(^YTHandlerEnterBackgroundBlock)(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime);
/** 处理进入后台并计算留在后台时间间隔类 */
@interface YTHandlerEnterBackground : NSObject
/** 添加观察者并处理后台 */
+ (void)addObserverUsingBlock:(nullable YTHandlerEnterBackgroundBlock)block;
/** 移除后台观察者 */
+ (void)removeNotificationObserver:(nullable id)observer;
@end

在YTHandlerEnterBackground.m实现文件中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//
// YTHandlerEnterBackground.m
// 分时租赁
//
// Created by 柯其谱 on 17/2/24.
// Copyright © 2017年 柯其谱. All rights reserved.
//
#import "YTHandlerEnterBackground.h"
@implementation YTHandlerEnterBackground
+ (void)addObserverUsingBlock:(YTHandlerEnterBackgroundBlock)block {
  __block CFAbsoluteTime enterBackgroundTime;
  [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
    if (![note.object isKindOfClass:[UIApplication class]]) {
      enterBackgroundTime = CFAbsoluteTimeGetCurrent();
    }
  }];
  __block CFAbsoluteTime enterForegroundTime;
  [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
    if (![note.object isKindOfClass:[UIApplication class]]) {
      enterForegroundTime = CFAbsoluteTimeGetCurrent();
      CFAbsoluteTime timeInterval = enterForegroundTime-enterBackgroundTime;
      block? block(note, timeInterval): nil;
    }
  }];
}
+ (void)removeNotificationObserver:(id)observer {
  if (!observer) {
    return;
  }
  [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationDidEnterBackgroundNotification object:nil];
  [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationWillEnterForegroundNotification object:nil];
}
@end

该类实现了用来添加通知监听者并处理后台和移除通知监听者的方法,需要注意的是,在addObserverUsingBlock方法中,必须有if (![note.object isKindOfClass:[UIApplication class]])的判断,否则addObserverForName方法中的代码块会执行多次,此代码执行了两次。addObserverUsingBlock方法是在viewWillAppear方法中调用添加通知监听者,在viewWillDisappear方法中调用移除通知监听者。

例如,在使用了计时器NSTimer控制器中:

?
1
2
3
4
5
6
7
8
9
10
11
- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) {
    self.rentTimerInterval = self.rentTimerInterval-stayBackgroundTime;
  }];
}
- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  [self.timer invalidate];
  [YTHandlerEnterBackground removeNotificationObserver:self];
}

我定义了一个倒计时5分钟的计时器对象timer属性,并定义了一个计时器当前倒计时时间间隔rentTimerInterval属性,在添加通知监听者代码块中,rentTimerInterval等于进入后台时的倒计时时间间隔减去程序停留在后台的时间间隔,当计时器再次回到前台时,计时器此时的时间间隔是持续的。虽然计时器并未在后台持续运行,但是使用了此方法,同样实现了计时器的正确即时。

同样的,当程序存在位置更新功能时,当程序进入后台,位置服务对象会自动停止更新,此时的作法依然是调用上述两个处理进入后台的方法,使得程序进入后台后,再次开始定位:

在需要位置更新的类中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  self.locService.delegate = self;
  [self.locService startUserLocationService];
  //进入后台再进入前台重新开始定位
  [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) {
    [self.locService startUserLocationService];
  }];
}
- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  //停止定位
  self.locService.delegate = nil;
  [self.locService stopUserLocationService];
  //移除后台监听
  [YTHandlerEnterBackground removeNotificationObserver:self];
}

此处使用的是百度地图SDK

利用这种方法,像是计时器和位置更新等需要在后台运行的任务都可以实现相应的需求,只是麻烦的是,在任何需要的类中都要调用这两种方法,你可以根据自己的需求,在程序进入后台和再次回到前台时添加别的参数(通知对象参数是必须的),例如保存进入后台前的操作等等。或是定义不同的添加通知监听者的方法以实现不同的需求。

以上所述是小编给大家介绍的iOS应用进入后台后计时器和位置更新停止问题的解决办法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:http://www.cnblogs.com/keqipu/archive/2017/03/06/6511394.html

延伸 · 阅读

精彩推荐
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28