iOS-----后台运行

后台运行

  当应用程序进入后台时,系统会自动回调应用程序委托的applicationDidEnterBackground:方法。

应用可以在该方法中完成转入后台前需要做的准备工作,所有的应用需要做以下事情。

  释放所有可以释放的内存。

  保存用户数据或状态信息,所有没写入磁盘的文件或信息,在进入后台之前,都应该写入磁盘,因为程序可能在后台被杀死。

进入后台时释放内存

    当程序进入后台之后,为了确保获得最佳的用户体验,建议释放那些占用内存较大且可以重新获取的资源----

这是因为当应用处于后台时,iOS系统会优先终止那些占用内存大的应用。如果应用尽可能释放其所占用的内存,

那么应用就可以在后台存或更久。从这个角度来看,可以得到一个结论:应用暂停时所占用的内存减少,iOS彻底终止该应用的风险就越低。

如果应用没有启用ARC机制,程序需要在应用进入后台时,将那些需要释放的资源的引用计数变为0,从而让系统回收这些资源。

当应用转入前台时,系统需要重新恢复这些资源。

如果应用启用了ARC机制,程序只要在应用进入后台时,将应用那些需要释放的资源的变量赋为nil即可。当应用转入前台时,

系统需要重新恢复这些资源。

//  使用默认的通知中心监听应用转入前台的过程

//  应用转入前台时会向通知中心发送UIApplicationWillEnterForegroundNotification

//  从而激发enterFore:方法

[[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector:@selector(enterBack:) name:UIApplicationWillEnterForegroundNotification

object:[UIApplication sharedApplication]];

//  使用默认的通知中心监听应用转入前台的过程

//  应用转入前台时会向通知中心发送UIApplicationDidEnterBackgroundNotification

//  从而激发enterFore:方法

[[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector:@selector(enterBack:) name:UIApplicationDidEnterBackgroundNotification

object:[UIApplication sharedApplication]];

说明

上面程序控制当应用转入前台时,该视图控制器的enterFore:方法被调用;当应用转入后台时,该控制器的enterBack:方法被调用,下面是enterBack:方法的代码

 

- (void) enterBack:(NSNotification *)notification

{

   NSLog(@”—enterBack---”);

   // 转入后台时将可以迅速重建,而且占用内存较大的对象设为nil,以便系统释放内存  

bgLayer1.contents = nil;

bgLayer2.contents = nil;

ePlaneImage1 = nil;

}

说明

 由于该应用已经启用了ARC机制,因此上面方法只要将这些图片、音乐资源的变量设为nil,系统就可以回收这些图片、音乐资源所占用的内存。

    当应用再次转入前台时,该控制器的enterFore:方法被调用,该方法将负责再次加载这些图片、音乐资源。下面是enterFore:方法的代码。

代码片段

-  (void) enterFore:(NSNotification *)notification

{

    NSLog(@”===enterFore===”);

bgLayer1.contents = (id)[bgImage CGImage];

bgLayer2.contents = (id)[bgImage CGImage];

ePlaneImage1 = [UIImage imageNamed:@”e1”];

}

说明

  通过上面的处理方法,程序可以在应用转入后台时释放大部分内存,使得该应用在后台以少量内存运行,从而降低该应用被iOS系统终止的风险。当该应用转入前台时,系统将会再次初始化 这些资源,从而保证iOS应用可以迅速恢复。

进入后台时保存状态

当应用进入后台时,如果程序有一些状态数据没有保存,而iOS系统可能在内存紧张时终止该应用,那么就可能导致该应用丢失这些状态数据。

为了让应用不会丢失状态数据,程序可以在应用转入后台时记录应用状态,应用转入后台时将会调用视图控制器的enterBack:方法,因此在该方法后面增加如下代码:

     // 使用NSUserDefaults存储系统积分

   [[NSUserDefaults standardUserDefaults] setInteger:score forkey:@”score”];

    上面的代码只是简单地使用了NSUserDefault来保存程序状态。如果程序需要保存的状态数据较多,也可采用plist属性文件或者其他形式来保存程序状态。

     接下来同样可以在应用转入前台时恢复程序状态,应用转入前台时将会调用视图控制器的enterFore:方法,因此在该方法后面增加如下代码:

  // 使用NSUserDefaults读取系统已经保存的积分

  NSNumber* scoreNumber;

  if((scoreNumber = [[NSUserDefault standardUserDefaults]

objectForKey:@”score”]))

{

    score = scoreNumber.integerValue;

}

请求更多的后台时间

   当应用转入后台后,不要在主线程中执行超过5秒的任务,如果应用进入后台花费了太多时间(即applicationDidEnterBackground:方法的执行体花费太多时间),应用可能从内存中被删除.

   假如应用程序正在执行文件下载或文件传输等,当应用进入后台时,如果该任务还没有执行完成,应用转入后台该任务就会被暂停.千万不要强制在applicationDidEnterBackground:方法中直接完成该任务----因为这会导致应用进入后台花费太多时间,iOS系统可能直接从内存中删除该应用.正确的做法是: 以applicationDidEnterBackground:方法为平台,告诉系统进入后台还是更多的任务需要完成,从而向系统申请更多的后台时间.在这种方式下,当我们的应用处于后台时,即使用户正在使用其他应用,只要系统还是足够的内存,我们的应用就可以保存在内存中,iOS系统会保留应用运行一段时间。

为了请求更多的后台时间,按如下步骤执行:

1.调用UIApplication对象的beginBackgroundTaskWithExpirationHandler:方法请求获取更多的后台执行时间,该方法默认请求额外获得10分钟后台时间。该方法需要传入一个代码块作为参数,如果请求获取后台执行时间失败,将会执行该代码块。该变量可作为后台任务的标识符。

2.调用dispatch_async()方法将指定代码块提交给后台执行.

3.后台任务执行完成时,调用UIApplication对象的endBackgroundTask:方法结束后台任务

  例如如下示例应用,该应用在系统转入后台时请求了后台执行时间,然后启动一个代码块,该代码块循环100次,模拟执行一个耗时的下载任务.从该程序转入后台的执行过程可以看出,通过这种机制即可让iOS应用在后台执行更长时间.

下面是该应用的视图控制器类的实现部分代码

ViewController.m

@implementation ViewController

- (void)viewDidLoad

{

   [super viewDidLoad];

   // 使用默认的通知中心监听应用转入后台的过程

   //  应用转入后台时会向通知中心发送UIApplicationDidEnterBackgroundNotification

   // 从而激发enterBack:方法

   [[NSNotificationCenter defaultCenter]  addObserve:self

selector:@selector(enterBack:)

name:UIApplicationDidEnterBackgroundNotification

object:[UIApplication sharedApplication]];

}

- (void)enterBack:(NSNotification *)notification

{

   UIApplication *app = [UIApplication sharedApplication];

   // 定义一个UIBackgroundTaskIdentifier类型(本质就是NSUInteger)的变量

   // 该变量将作为后台任务的标识符

   __block UIBackgroundTaskIdentifier backTaskId;

   backTaskId = [app beginBackgroundTaskWithExpirationHandler:^

{

      NSLog(@”===在额外申请的10分钟内依然没有完成任务===”);

      // 结束后台任务

     [app endBackgroundTask:backTaskId];

}];

 if(backTaskId == UIBackgroundTaskInvalid)

{

   NSLog(@”===iOS版本不支持后台运行,后台任务启动失败===”);

   return;

}

// 将代码块以异步方式提交给系统的全局并发队列

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

, ^{

    NSLog(@”===额外申请的后台任务时间为: %f===”

,  app.backgroundTimeRemaining);

// 其他内存清理的代码也可以在此处完成

for(int i = 0 ; i < 100 ; i++)

{

     NSLog(@”下载任务完成了%d%%” , i);// 转换成百分比

// 暂停10秒模拟正在执行后台下载

[NSThread sleepForTimeInterval:10];

}

NSLog(@”===剩余的后台任务时间为: %f===”

,  app.backgroundTimeRemaining);

// 结束后台任务

[app endBackgroundTask:backTaskId];

});

}

@end

 

 

posted @ 2015-12-04 17:15    阅读(955)  评论(0编辑  收藏  举报