值得做的事情,就是值得做对的事情。
前言
昨天小伙伴有个需求,就是用户在杀掉app后,要把一些用户习惯信息的保存到本地。实现起来很简单,就是在Appdelegate
中的applicationWillTerminate
的代理方法里面写相应的业务代码就行了。但是问题来了,保存本地失灵时不灵的,仔细一看原来他用dispatch_barrier_async
实现了一个多读单写,在写的时候是异步,所以出现了上面的问题。
代码简化后大致思想如下:
dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
//模拟耗时处理
sleep(1);
NSLog(@">>>>do something");
});
先抛开其它的不谈,就上面的问题的本质是 杀掉app时,仍执行异步任务。对此,目前我想到两种解决方式。
Demo地址:传送门
- 第一种,使用信号量
dispatch_semaphore_t
dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
dispatch_async(queue, ^{
//模拟耗时处理
sleep(1);
NSLog(@">>>>do something");
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
- 第二种,线程常驻
- (void)residentThread {
///!!!:放在前面不行,要放在后面
// [self performSelector:@selector(run) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES];
dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
//模拟耗时处理
sleep(2);
[self.timer invalidate];
self.timer = nil;
NSLog(@">>>>do something");
});
[self performSelector:@selector(run) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES];
}
- (void)run {
NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(go) userInfo:nil repeats:YES];
[timer fire];
self.timer = timer;
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
///!!!:放在后面任务处理完后,还在继续
// self.timer = timer;
}
- (void)go {
NSLog(@">>>timer");
}
总结
不管是哪种,本质都是阻塞主线程,然后后台继续执行任务。
- 优势
可以实现杀掉APP,后台任务执行。
- 潜在问题
如果这个任务很耗时,那么就会一直阻塞,在任务没有完成之前再次打开app时,会卡住。这时需要做相应处理。
后记
线程常驻那部分有2点标记重要,有兴趣的小伙伴可以研究一下。
网友评论