// AppDelegate.h
#import
@interface AppDelegate : UIResponder
@property (strong, nonatomic) UIWindow *window;
@end
// AppDelegate.m
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid) {
bgTask = UIBackgroundTaskInvalid;
}
});
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid) {
bgTask = UIBackgroundTaskInvalid;
}
});
});
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
@end
// ViewController.h
#import
@interface ViewController : UIViewController
@end
// ViewController.m
#import "ViewController.h"
#import "CountDownManager.h"
@interface ViewController ()
@property (nonatomic, strong)UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[kCountDownManager start];//开始倒计时
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
self.label = [[UILabel alloc]initWithFrame:CGRectMake((screenWidth - 300)/2, 300, 300, 100)];
self.label.textColor = [UIColor greenColor];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.numberOfLines = 0;
[self.view addSubview:self.label];
// 监听通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(countDownNotification) name:CountDownNotification object:nil];
}
- (NSString *)convertTimeIntervalToFormatDate:(NSTimeInterval)timeInterval {
//初始时间格式化对象
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
//设置时间格式
dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
//时间戳转时间
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
return [dateFormatter stringFromDate:date];
}
- (NSMutableAttributedString *)getCountdownAttributStringWithStringOne:(NSString *)stringOne stringTwo:(NSString *)stringTwo{
NSString * str = [self convertTimeIntervalToFormatDate:1557973398];
//初始化可变富文本对象
NSMutableAttributedString *string1 = [[NSMutableAttributedString alloc]initWithString:stringOne];
NSMutableAttributedString *string2 = [[NSMutableAttributedString alloc]initWithAttributedString:[self getNowTimeWithString:str]];
NSMutableAttributedString *string3 = [[NSMutableAttributedString alloc]initWithString:stringTwo];
//拼接属性化字符串
[string1 appendAttributedString:string2];
[string1 appendAttributedString:string3];
//初始化可变的段落样式,用于设置首行,行间距,对齐方式等
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
//设置字体的行间距
[style setLineSpacing:1];
[string1 addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, string1.length)];
return string1;
}
- (NSAttributedString *)getNowTimeWithString:(NSString *)aTimeString {
NSDateFormatter *formater = [[NSDateFormatter alloc] init];
[formater setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *expireDate = [formater dateFromString:aTimeString];
NSDate *nowDate = [NSDate date];
NSString *nowDateStr = [formater stringFromDate:nowDate];
nowDate = [formater dateFromString:nowDateStr];
//时间转时间戳
NSTimeInterval timeInterval =[expireDate timeIntervalSinceDate:nowDate];
//倒计时的计算
int days = (int)(timeInterval/(3600*24));
int hours = (int)((timeInterval-days*24*3600)/3600);
int minutes = (int)(timeInterval-days*24*3600-hours*3600)/60;
int seconds = timeInterval-days*24*3600-hours*3600-minutes*60;
NSString *dayStr = nil;
NSString *hoursStr = nil;
NSString *minutesStr = nil;
NSString *secondsStr = nil;
dayStr = [NSString stringWithFormat:@"%d",days];
hoursStr = [NSString stringWithFormat:@"%d",hours];
if(minutes < 10) {
minutesStr = [NSString stringWithFormat:@"0%d", minutes];
} else {
minutesStr = [NSString stringWithFormat:@"%d", minutes];
}
if(seconds < 10) {
secondsStr = [NSString stringWithFormat:@"0%d", seconds];
} else {
secondsStr = [NSString stringWithFormat:@"%d", seconds];
}
if (hours <= 0 &&
minutes <= 0 &&
seconds <= 0) {
//倒计时结束
[kCountDownManager invalidate];
NSString *nowTimeStr = @"0天0小时0分0秒";
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc]initWithString:nowTimeStr];
return attributeString;
}
NSString *nowTimeStr = [NSString stringWithFormat:@"%@ 天%@ 小时%@ 分%@ 秒", dayStr, hoursStr, minutesStr, secondsStr];
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc]initWithString:nowTimeStr];
//设置富文本颜色
[attributeString setAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]} range:NSMakeRange(0, nowTimeStr.length)];
return attributeString;
}
-(NSDate *)DateFromTimeStamap:(NSString *)timeStamap{
//传入的时间戳timeStamap如果是精确到毫秒要/1000
NSTimeInterval timeInterval = [timeStamap doubleValue]/1000;
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
return date;
}
- (void)countDownNotification {
//赋值给label
self.label.attributedText = [self getCountdownAttributStringWithStringOne:@"火箭还有" stringTwo:@"发射"];
}
-(void)dealloc{
// 废除定时器
[kCountDownManager invalidate];
// 清空时间差
[kCountDownManager reload];
}
@end
// CountDownManager.h
#import
/** 宏: 使用单例 */
#define kCountDownManager [CountDownManager manager]
/** 倒计时的通知名 */
extern NSString *const CountDownNotification;
@interface CountDownManager : NSObject
/** 使用单例 */
+ (instancetype)manager;
/** 开始倒计时 */
- (void)start;
/** 停止倒计时 */
- (void)invalidate;
// ======== v1.0 ========
// 如果只需要一个倒计时差, 可继续使用timeInterval属性
// 增加后台模式, 后台状态下会继续计算时间差
/** 时间差(单位:秒) */
@property (nonatomic, assign) NSInteger timeInterval;
/** 刷新倒计时(兼容旧版本, 如使用identifier标识的时间差, 请调用reloadAllSource方法) */
- (void)reload;
// ======== v2.0 ========
// 增加identifier:标识符, 一个identifier支持一个倒计时源, 有一个单独的时间差
/** 添加倒计时源 */
- (void)addSourceWithIdentifier:(NSString *)identifier;
/** 获取时间差 */
- (NSInteger)timeIntervalWithIdentifier:(NSString *)identifier;
/** 刷新倒计时源 */
- (void)reloadSourceWithIdentifier:(NSString *)identifier;
/** 刷新所有倒计时源 */
- (void)reloadAllSource;
/** 清除倒计时源 */
- (void)removeSourceWithIdentifier:(NSString *)identifier;
/** 清除所有倒计时源 */
- (void)removeAllSource;
@end
@interface OYTimeInterval : NSObject
@end
// CountDownManager.m
#import "CountDownManager.h"
#import
@interface OYTimeInterval ()
@property (nonatomic, assign) NSInteger timeInterval;
+ (instancetype)timeInterval:(NSInteger)timeInterval;
@end
@implementation OYTimeInterval
+ (instancetype)timeInterval:(NSInteger)timeInterval {
OYTimeInterval *object = [OYTimeInterval new];
object.timeInterval = timeInterval;
return object;
}
@end
NSString *const CountDownNotification = @"CountDownNotification";
@interface CountDownManager()
@property (nonatomic, strong) NSTimer *timer;
/// 时间差字典(单位:秒)(使用字典来存放, 支持多列表或多页面使用)
@property (nonatomic, strong) NSMutableDictionary *timeIntervalDict;
/// 后台模式使用, 记录进入后台的绝对时间
@property (nonatomic, assign) BOOL backgroudRecord;
@property (nonatomic, assign) CFAbsoluteTime lastTime;
@end
@implementation CountDownManager
+ (instancetype)manager {
static CountDownManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[CountDownManager alloc]init];
});
return manager;
}
- (instancetype)init {
self = [super init];
if (self) {
// 监听进入前台与进入后台的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackgroundNotification) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForegroundNotification) name:UIApplicationWillEnterForegroundNotification object:nil];
}
return self;
}
//开始倒计时
- (void)start {
// 启动定时器
[self timer];
}
//刷新倒计时
- (void)reload {
// 刷新只要让时间差为0即可
_timeInterval = 0;
}
//停止倒计时
- (void)invalidate {
[self.timer invalidate];
self.timer = nil;
}
- (void)timerAction {
// 定时器每次加1
[self timerActionWithTimeInterval:1];
}
- (void)timerActionWithTimeInterval:(NSInteger)timeInterval {
// 时间差+
self.timeInterval += timeInterval;
[self.timeIntervalDict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, OYTimeInterval * _Nonnull obj, BOOL * _Nonnull stop) {
obj.timeInterval += timeInterval;
}];
// 发出通知
[[NSNotificationCenter defaultCenter] postNotificationName:CountDownNotification object:nil userInfo:nil];
}
//添加倒计时源
- (void)addSourceWithIdentifier:(NSString *)identifier {
OYTimeInterval *timeInterval = self.timeIntervalDict[identifier];
if (timeInterval) {
timeInterval.timeInterval = 0;
}else {
[self.timeIntervalDict setObject:[OYTimeInterval timeInterval:0] forKey:identifier];
}
}
//获取时间差
- (NSInteger)timeIntervalWithIdentifier:(NSString *)identifier {
return self.timeIntervalDict[identifier].timeInterval;
}
//刷新倒计时源
- (void)reloadSourceWithIdentifier:(NSString *)identifier {
self.timeIntervalDict[identifier].timeInterval = 0;
}
//刷新所有倒计时源
- (void)reloadAllSource {
[self.timeIntervalDict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, OYTimeInterval * _Nonnull obj, BOOL * _Nonnull stop) {
obj.timeInterval = 0;
}];
}
//清除倒计时源
- (void)removeSourceWithIdentifier:(NSString *)identifier {
[self.timeIntervalDict removeObjectForKey:identifier];
}
//清除所有倒计时源
- (void)removeAllSource {
[self.timeIntervalDict removeAllObjects];
}
//接受到程序进入后台的回调方法
- (void)applicationDidEnterBackgroundNotification {
self.backgroudRecord = (_timer != nil);
if (self.backgroudRecord) {
self.lastTime = CFAbsoluteTimeGetCurrent();
[self invalidate];
}
}
//接受到程序回到前台的回调方法
- (void)applicationWillEnterForegroundNotification {
if (self.backgroudRecord) {
CFAbsoluteTime timeInterval = CFAbsoluteTimeGetCurrent() - self.lastTime;
// 取整
[self timerActionWithTimeInterval:(NSInteger)timeInterval];
[self start];
}
}
//初始化定时器
- (NSTimer *)timer {
if (_timer == nil) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
//RunLoop是一个对象,这个对象在循环中用来处理程序运行过程中出现的各种事件(比如说触摸事件、UI刷新事件、定时器事件、Selector事件),从而保持程序的持续运行;而且在没有事件处理的时候,会进入睡眠模式,从而节省CPU资源,提高程序性能。
//[NSRunLoop mainRunLoop]获得主线程的RunLoop对象
[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
}
return _timer;
}
//可变字典懒加载
- (NSMutableDictionary *)timeIntervalDict {
if (!_timeIntervalDict) {
_timeIntervalDict = [NSMutableDictionary dictionary];
}
return _timeIntervalDict;
}
@end
开始倒计时
结束倒计时