前言
我們一般做的短信驗(yàn)證碼功能哈恰,應(yīng)用在前臺(tái)運(yùn)行的時(shí)候,肯定是沒有問題的臼氨,但是點(diǎn)擊一下Home鍵進(jìn)入后臺(tái)掛起的狀態(tài)掺喻,我們的定時(shí)器就停止了。
網(wǎng)上很多說記錄什么進(jìn)入后臺(tái)的時(shí)間储矩,我覺的那太費(fèi)事了感耙,我們完全可以通過申請(qǐng)應(yīng)用在后臺(tái)執(zhí)行來執(zhí)行我們的倒計(jì)時(shí)。
1持隧、先放我們倒計(jì)時(shí)的代碼即硼,這段代碼在模擬器運(yùn)行是沒有問題的,但是在真機(jī)進(jìn)入掛起狀態(tài)會(huì)停止
<pre>
-
(void)sentPhoneCodeTimeMethod {
//倒計(jì)時(shí)時(shí)間 - 60S
__block NSInteger timeOut = 59;
//執(zhí)行隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//計(jì)時(shí)器 -》 dispatch_source_set_timer自動(dòng)生成
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);dispatch_source_set_event_handler(timer, ^{
if (timeOut <= 0) {
dispatch_source_cancel(timer);
//主線程設(shè)置按鈕樣式
dispatch_async(dispatch_get_main_queue(), ^{
// 倒計(jì)時(shí)結(jié)束
[self.captchaButton setBackgroundImage:kImage(kCaptchaButtonNormal) forState:UIControlStateNormal];
[self.captchaButton setTitle:kCaptchaButtonTitle forState:UIControlStateNormal];
[self.captchaButton setEnabled:YES];[self.captchaButton setUserInteractionEnabled:YES]; }); } else { //開始計(jì)時(shí) //剩余秒數(shù) seconds NSInteger seconds = timeOut % 60; NSString *strTime = [NSString stringWithFormat:@"%.1ld", seconds]; //主線程設(shè)置按鈕樣式 dispatch_async(dispatch_get_main_queue(), ^{ [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:1.0]; [self.captchaButton setBackgroundImage:kImage(kCaptchaButtonSelected) forState:UIControlStateNormal]; NSString *title = [NSString stringWithFormat:@"%@ s",strTime]; [self.captchaButton setTitle:title forState:UIControlStateNormal]; [UIView commitAnimations]; //計(jì)時(shí)器件不允許點(diǎn)擊 [self.captchaButton setUserInteractionEnabled:NO]; }); timeOut--; }
});
dispatch_resume(timer);
}
</pre>
2屡拨、下面是我們用到的一個(gè)小技巧
一般來說只酥,如果不進(jìn)行后臺(tái)申請(qǐng)褥实,在iOS系統(tǒng)上,當(dāng)應(yīng)用退到后臺(tái)后裂允,只有5s的時(shí)間去執(zhí)行代碼损离,之后將進(jìn)入掛起狀態(tài)。只有像音頻播放绝编、定位草冈、newsstand、VoIP等功能才能持續(xù)在后臺(tái)運(yùn)行瓮增。但是開發(fā)其它應(yīng)用是我們可以通過申請(qǐng)后臺(tái)怎棱,來獲得3分鐘的后臺(tái)執(zhí)行代碼時(shí)間(iOS7以前是10分鐘)。
所以我們決定申請(qǐng)3分鐘來執(zhí)行我們1分鐘的倒計(jì)時(shí)代碼:
<pre>
import "AppDelegate.h"
@interface AppDelegate (){
NSInteger count;
}
@property(strong, nonatomic)NSTimer *mTimer;
@property(assign, nonatomic)UIBackgroundTaskIdentifier backIden;
@end
@implementation AppDelegate
-
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.count=0;
return YES;
} (void)applicationDidEnterBackground:(UIApplication *)application {
_mTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countAction) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_mTimer forMode:NSRunLoopCommonModes];
[self beginTask];
}(void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(@"進(jìn)入前臺(tái)");
[self endBack];
}
//計(jì)時(shí)
-(void)countAction{
NSLog(@"%li",count++);
}
//申請(qǐng)后臺(tái)
-(void)beginTask
{
NSLog(@"begin=============");
_backIden = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
//在時(shí)間到之前會(huì)進(jìn)入這個(gè)block绷跑,一般是iOS7及以上是3分鐘拳恋。按照規(guī)范,在這里要手動(dòng)結(jié)束后臺(tái)砸捏,你不寫也是會(huì)結(jié)束的(據(jù)說會(huì)crash)
NSLog(@"將要掛起=============");
[self endBack];
}];
}
//注銷后臺(tái)
-(void)endBack
{
NSLog(@"end=============");
[[UIApplication sharedApplication] endBackgroundTask:_backIden];
_backIden = UIBackgroundTaskInvalid;
}
@end
</pre>
這樣就輕松谬运、完美解決了我們的需求了!?巡亍梆暖!
3、 擴(kuò)充無限倒計(jì)時(shí)
慎用掂骏!因?yàn)檫@個(gè)需要申請(qǐng)后臺(tái)播放音頻的權(quán)限轰驳。如果你的應(yīng)用不是相關(guān)應(yīng)用,AppStore審核可能不會(huì)通過弟灼。
先在我們的info.plist文件配置中级解,添加一行,如下兩個(gè)屬性:
Required background modes
App plays audio or streams audio/video using AirPlay
AppDelegate.m文件中代碼還是和上面一樣田绑,設(shè)置 UIBackgroundTaskIdentifier
<pre>
import "AppDelegate.h"
@interface AppDelegate (){
NSInteger count;
}
@property(strong, nonatomic)NSTimer *mTimer;
@property(assign, nonatomic)UIBackgroundTaskIdentifier backIden;
@end
@implementation AppDelegate
-
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.count=0;
return YES;
} (void)applicationDidEnterBackground:(UIApplication *)application {
_mTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countAction) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_mTimer forMode:NSRunLoopCommonModes];
[self beginTask];
}(void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(@"進(jìn)入前臺(tái)");
[self endBack];
}
//計(jì)時(shí)
-(void)countAction{
NSLog(@"%li",count++);
}
//申請(qǐng)后臺(tái)
-(void)beginTask
{
NSLog(@"begin=============");
_backIden = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"將要掛起=============");
[self endBack];
}];
}
//注銷后臺(tái)
-(void)endBack
{
NSLog(@"end=============");
[[UIApplication sharedApplication] endBackgroundTask:_backIden];
_backIden = UIBackgroundTaskInvalid;
}
@end
</pre>
在我們需要后臺(tái)運(yùn)行的控制器中勤哗,例如ViewController.m
<pre>
import "ViewController.h"
import <AVFoundation/AVFoundation.h>
@interface ViewController ()
@property(strong, nonatomic)AVAudioPlayer *mPlayer;
@property(assign, nonatomic)CGFloat mCount;
@end
@implementation ViewController
-
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib._mCount = 0;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(countTime) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
-(void)countTime{
_mCount+=10;
NSLog(@"%f",_mCount);
if ([[UIApplication sharedApplication] backgroundTimeRemaining] < 60.) {//當(dāng)剩余時(shí)間小于60時(shí),開如播放音樂掩驱,并用這個(gè)假前臺(tái)狀態(tài)再次申請(qǐng)后臺(tái)
NSLog(@"播放%@",[NSThread currentThread]);
[self playMusic];
//申請(qǐng)后臺(tái)
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"我要掛起了");
}];
}
}
-(void)playMusic{
//1.音頻文件的url路徑芒划,實(shí)際開發(fā)中,用無聲音樂
NSURL *url=[[NSBundle mainBundle]URLForResource:@"歡沁.mp3" withExtension:Nil];
//2.創(chuàng)建播放器(注意:一個(gè)AVAudioPlayer只能播放一個(gè)url)
_mPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:Nil];
//3.緩沖
[_mPlayer prepareToPlay];
//4.播放
[_mPlayer play];
}
@end
</pre>
完欧穴。
自助者民逼,天助之。