PINCache中的后台任务
在PINCache磁盘缓存策略中,针对数据写入,删除等磁盘操作,作者用了后台任务操作,用来确保磁盘操作得以顺利完成。其具体是通过beginBackgroundTaskWithExpirationHandler来实现的。作者对其操作进行了封装。在源码中有一个PINBackgroundTask类,该类实现了向系统注册后台任务的方法。
这里有几点需要明确下:
大多数情况下,我们可以在app中通过调用beginBackgroundTaskWithExpirationHandler来请求一个后台任务,通过调用endBackgroundTask来完成该请求。几乎不会在用户按下Home键的时候来调用。
你可以在任何时候,同时向系统请求多个任务。这对于系统来说,性能损耗较低,就好比引用计数一样,只要系统中还有一个未完成的请求,系统就会预留一些时间来完成它。
系统是不能保证用户的请求同步完成。这些方法只是向系统请求,系统仍可以忽略该请求,在需要一些额外的资源,甚至可能被系统然随时杀了进程。系统通常会预留约10分钟时间来处理请求。
动手写一个
-
检查系统是否支持多线程任务
if([][UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupportes)]) { }
-
向系统请求一个后台任务
__block UIBackgroundTaskIdentifier background_task; background_task = [application beginBackgroundTaskWithExpirationHandler:^ { //This code block is execute when the application’s //remaining background time reaches ZERO.}];
-
执行自己的异步操作,并标志请求完成
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //### background task starts NSLog(@"Running in the background\n"); while(TRUE) { NSLog(@"Background time Remaining: %f",[[UIApplication sharedApplication] backgroundTimeRemaining]); [NSThread sleepForTimeInterval:1]; //wait for 1 sec } //#### background task ends //Clean up code. Tell the system that we are done. [application endBackgroundTask: background_task]; background_task = UIBackgroundTaskInvalid; });
看看PINCache的具体实现
@interface PINBackgroundTask : NSObject
#if !defined(PIN_APP_EXTENSIONS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
@property (atomic, assign) UIBackgroundTaskIdentifier taskID;
#endif
+ (instancetype)start;
- (void)end;
@end
@implementation PINBackgroundTask
- (instancetype)init
{
if (self = [super init]) {
#if !defined(PIN_APP_EXTENSIONS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
_taskID = UIBackgroundTaskInvalid;
#endif
}
return self;
}
+ (instancetype)start
{
PINBackgroundTask *task = [[self alloc] init];
#if !defined(PIN_APP_EXTENSIONS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
task.taskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
UIBackgroundTaskIdentifier taskID = task.taskID;
task.taskID = UIBackgroundTaskInvalid;
[[UIApplication sharedApplication] endBackgroundTask:taskID];
}];
#endif
return task;
}
- (void)end
{
#if !defined(PIN_APP_EXTENSIONS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
UIBackgroundTaskIdentifier taskID = self.taskID;
self.taskID = UIBackgroundTaskInvalid;
[[UIApplication sharedApplication] endBackgroundTask:taskID];
#endif
}
@end
具体使用
- (void)removeObjectForKey:(NSString *)key fileURL:(NSURL **)outFileURL
{
if (!key)
return;
//创建一个后台请求
PINBackgroundTask *task = [PINBackgroundTask start];
NSURL *fileURL = nil;
[self lock];
fileURL = [self encodedFileURLForKey:key];
[self removeFileAndExecuteBlocksForKey:key];
[self unlock];
//注销完成该请求
[task end];
if (outFileURL) {
*outFileURL = fileURL;
}
}