最近想整理下關于OC的工具類,常用到的也方便自己之后查閱,也可以給需要的朋友參考。
1、兩種倒計時
-
第一種:
GCD
__block NSInteger timeout = time;//可以假設time等于60秒
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒執(zhí)行
dispatch_source_set_event_handler(_timer, ^{
if(timeout<=0){ //倒計時結束,關閉
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
//主線程中處理UI
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
//主線程中處理UI
presellTimeLB.text = [self dateFormatDays_Hours_MinsWith:timeout];
});
timeout--;
}
});
dispatch_resume(_timer);
這里我假設我有一個名為presellTimeLB
的Label,處理倒計時的方法dateFormatDays_Hours_MinsWith:
(僅供參考)
- (NSString *)dateFormatDays_Hours_MinsWith:(NSInteger)time
{
NSInteger days = 0,hours = 0,minutes = 0,second = 0;
NSInteger daySeconds = 24*60*60;
//獲取天數(shù)
if (time >= daySeconds) {
days = time/daySeconds;
time = time%daySeconds;
}
//獲取小時數(shù)
if(time>=60*60){
hours = time/3600;
time = time%3600;
}
//獲取分鐘數(shù)
if (time>=60) {
minutes = time/60;
time = time%60;
}
//獲取秒數(shù)
second = time;
if (days>0) {
return [NSString stringWithFormat:@"%ld天%ld時%ld分",(long)days,(long)hours,(long)minutes];
}else{
return [NSString stringWithFormat:@"%ld時%ld分%ld秒",(long)hours,(long)minutes,(long)second];
}
}
-
第二種:
NSTimer
1)聲明
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES];
2)實現(xiàn)select方法
- (void)timerFireMethod:(NSTimer *)theTimer
{
timer = theTimer;
static NSInteger hhh;
if (timeStart) {
hhh = [self.leftTime integerValue];
timeStart = NO;
}
if (hhh <= 1) {
preSellView.hidden = YES;
//注①
[timer invalidate];
}else {
//注②
[[NSRunLoop currentRunLoop] addTimer:theTimer forMode:NSRunLoopCommonModes];
hhh--;
dispatch_async(dispatch_get_main_queue(), ^{
[presellTimeLB setText:[self dateFormatDays_Hours_MinsWith:hhh]];
});
}
}
注:
①NSTimer
對象用完之后必須進行invalidate
,NSTimer
才會消失。比如說你還需要考慮到倒計時沒結束時退出當前頁面時是不是也需要把當前的NSTimer invalidate
呢?
②這里為什么要用NSRunLoop
寫這句代碼呢?如果沒有這句代碼,會發(fā)現(xiàn)在界面上滾動一個scrollView
,那么滾動停止前,timer像是暫停了一樣,其實這是runloop的mode在作怪。
runloop
可以理解為cocoa下的一種消息循環(huán)機制,用來處理各種消息事件,我們在開發(fā)的時候并不需要手動去創(chuàng)建一個runloop
,因為框架為我們創(chuàng)建了一個默認的runloop
,通過[NSRunloop currentRunloop]
我們可以得到一個當前線程下面對應的runloop
對象,不過我們需要注意的是不同的runloop
之間消息的通知方式。
在開啟一個NSTimer
實質(zhì)上是在當前的runloop
中注冊了一個新的事件源,而當scrollView
滾動的時候,當前的MainRunLoop
是處于UITrackingRunLoopMode
的模式下,在這個模式下,是不會處理NSDefaultRunLoopMode
的消息(因為RunLoop Mode不一樣),要
要想在scrollView
滾動的同時也響應其他runloop
的消息,需要改變兩者之間的runloopMode
.
[[NSRunLoop currentRunLoop] addTimer:theTimer forMode:NSRunLoopCommonModes];
-
NSTimer 的另一種寫法
- (void)timerFireMethod:(NSTimer *)theTimer
{
NSCalendar *cal = [NSCalendar currentCalendar];//定義一個NSCalendar對象
NSDateComponents *endTime = [[NSDateComponents alloc] init]; //初始化目標時間...
NSDate *today = [NSDate date]; //得到當前時間
NSDate *date = [NSDate dateWithTimeInterval:80 sinceDate:today];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *dateString = [dateFormatter stringFromDate:date];
static int year;
static int month;
static int day;
static int hour;
static int minute;
static int second;
if(timeStart) {//從NSDate中取出年月日,時分秒,但是只能取一次
year = [[dateString substringWithRange:NSMakeRange(0, 4)] intValue];
month = [[dateString substringWithRange:NSMakeRange(5, 2)] intValue];
day = [[dateString substringWithRange:NSMakeRange(8, 2)] intValue];
hour = [[dateString substringWithRange:NSMakeRange(11, 2)] intValue];
minute = [[dateString substringWithRange:NSMakeRange(14, 2)] intValue];
second = [[dateString substringWithRange:NSMakeRange(17, 2)] intValue];
timeStart= NO;
}
[endTime setYear:year];
[endTime setMonth:month];
[endTime setDay:day];
[endTime setHour:hour];
[endTime setMinute:minute];
[endTime setSecond:second];
NSDate *todate = [cal dateFromComponents:endTime]; //把目標時間裝載入date
//用來得到具體的時差,是為了統(tǒng)一成北京時間
unsigned int unitFlags = NSYearCalendarUnit| NSMonthCalendarUnit| NSDayCalendarUnit| NSHourCalendarUnit| NSMinuteCalendarUnit| NSSecondCalendarUnit;
NSDateComponents *d = [cal components:unitFlags fromDate:today toDate:todate options:0];
NSString *h = [NSString stringWithFormat:@"%ld",(long)[d hour]];
NSString *fen = [NSString stringWithFormat:@"%ld", (long)[d minute]];
if([d minute] < 10) {
fen = [NSString stringWithFormat:@"%ld",[d minute]];
}
NSString *miao = [NSString stringWithFormat:@"%ld", (long)[d second]];
if([d second] < 10) {
miao = [NSString stringWithFormat:@"0%ld",(long)[d second]];
}
if([d second] >= 0) {
//計時尚未結束,do_something
dispatch_async(dispatch_get_main_queue(), ^{
[[NSRunLoop currentRunLoop] addTimer:theTimer forMode:NSRunLoopCommonModes];
[presellTimeLB setText:[NSString stringWithFormat:@"%ld時%ld分%ld秒",[h integerValue],[fen integerValue], [miao integerValue]]];
});
} else{
//倒計時結束,do something
[theTimer invalidate];
}
}
注:這里我們以80
秒倒計時為例,還是假設我有一個BOOL
類型的timeStart
為了取一次原始時間,有名為presellTimeLB
的Laber,nsrunloop
改變mode的狀態(tài)照樣寫上。這里把時間處理和邏輯判斷寫在了一起。