YMTimer.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. //
  2. // YMTimer.m
  3. // yuemoClient
  4. //
  5. // Created by YoMi on 2023/11/6.
  6. //
  7. #import "YMTimer.h"
  8. #define YMPopupViewTimerPath(name) [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"YMTimer_%@_Timer",name]]
  9. @interface YMPopupViewTimerModel : NSObject
  10. /** 毫秒为单位计算 */
  11. @property (nonatomic, assign) NSTimeInterval time;
  12. /** 原始开始时间 毫秒 */
  13. @property (nonatomic, assign) NSTimeInterval originalTime;
  14. /** 进度单位 */
  15. @property (nonatomic, assign) NSTimeInterval unit;
  16. /** 是否本地持久化保存定时数据 */
  17. @property (nonatomic,assign) BOOL isDisk;
  18. /** 是否暂停 */
  19. @property (nonatomic,assign) BOOL isPause;
  20. /** 标识 */
  21. @property (nonatomic, copy) NSString *identifier;
  22. /** 通知名称 */
  23. @property (nonatomic, copy) NSString *NFName;
  24. /** 通知类型 0.不发通知 1.毫秒通知 2.秒通知 */
  25. @property (nonatomic, assign) YMTimerSecondChangeNFType NFType;
  26. /** 定时器更改block */
  27. @property (nonatomic, copy) YMTimerChangeBlock handleBlock;
  28. /** 定时器完成block */
  29. @property (nonatomic, copy) YMTimerFinishBlock finishBlock;
  30. /** 定时器暂停block */
  31. @property (nonatomic, copy) YMTimerPauseBlock pauseBlock;
  32. + (instancetype)timeInterval:(NSInteger)timeInterval;
  33. @end
  34. @implementation YMPopupViewTimerModel
  35. + (instancetype)timeInterval:(NSInteger)timeInterval {
  36. YMPopupViewTimerModel *object = [YMPopupViewTimerModel new];
  37. object.time = timeInterval*1000;
  38. object.originalTime = timeInterval*1000;
  39. return object;
  40. }
  41. - (void)encodeWithCoder:(NSCoder *)aCoder {
  42. [aCoder encodeDouble:self.time forKey:@"timeInterval"];
  43. [aCoder encodeDouble:self.originalTime forKey:@"oriTime"];
  44. [aCoder encodeDouble:self.unit forKey:@"unit"];
  45. [aCoder encodeBool:self.isDisk forKey:@"isDisk"];
  46. [aCoder encodeBool:self.isPause forKey:@"isPause"];
  47. [aCoder encodeObject:self.identifier forKey:@"identifier"];
  48. [aCoder encodeBool:self.NFType forKey:@"NFType"];
  49. }
  50. - (id)initWithCoder:(NSCoder *)aDecoder {
  51. self = [super init];
  52. if (self) {
  53. self.time = [aDecoder decodeDoubleForKey:@"timeInterval"];
  54. self.originalTime = [aDecoder decodeDoubleForKey:@"oriTime"];
  55. self.unit = [aDecoder decodeDoubleForKey:@"unit"];
  56. self.isDisk = [aDecoder decodeBoolForKey:@"isDisk"];
  57. self.isPause = [aDecoder decodeBoolForKey:@"isPause"];
  58. self.identifier = [aDecoder decodeObjectForKey:@"identifier"];
  59. self.NFType = [aDecoder decodeBoolForKey:@"NFType"];
  60. }
  61. return self;
  62. }
  63. @end
  64. @interface YMTimer ()
  65. @property (nonatomic, strong) NSTimer * _Nullable showTimer;
  66. /** 储存多个计时器数据源 */
  67. @property (nonatomic, strong) NSMutableDictionary<NSString *, YMPopupViewTimerModel *> *timerMdic;
  68. @end
  69. @implementation YMTimer
  70. static YMTimer *_instance;
  71. YMTimer *YMTimerM() {
  72. return [YMTimer sharedInstance];
  73. }
  74. + (instancetype)sharedInstance {
  75. if (!_instance) {
  76. static dispatch_once_t onceToken;
  77. dispatch_once(&onceToken, ^{
  78. _instance = [[self alloc] init];
  79. });
  80. }
  81. return _instance;
  82. }
  83. + (id)allocWithZone:(struct _NSZone *)zone {
  84. static dispatch_once_t onceToken;
  85. dispatch_once(&onceToken, ^{
  86. _instance = [super allocWithZone:zone];
  87. });
  88. return _instance;
  89. }
  90. /// 设置倒计时任务的通知回调
  91. /// @param name 通知名
  92. /// @param identifier 倒计时任务的标识
  93. /// @param type 倒计时变化通知类型
  94. + (void)setNotificationForName:(NSString *)name identifier:(NSString *)identifier changeNFType:(YMTimerSecondChangeNFType)type {
  95. if (identifier.length<=0) {
  96. NSLog(@"计时器标识不能为空");
  97. return;
  98. }
  99. YMPopupViewTimerModel *model = YMTimerM().timerMdic[identifier];
  100. if (model) {
  101. model.NFType = type;
  102. model.NFName = name;
  103. return;
  104. }else {
  105. NSLog(@"找不到计时器任务");
  106. return;
  107. }
  108. }
  109. /** 添加定时器并开启计时 */
  110. + (void)addTimerForTime:(NSTimeInterval)time handle:(YMTimerChangeBlock)handle {
  111. [self initTimerForForTime:time identifier:nil ForIsDisk:NO unit:0 handle:handle finish:nil pause:nil];
  112. }
  113. /** 添加定时器并开启计时 */
  114. + (void)addTimerForTime:(NSTimeInterval)time
  115. identifier:(NSString *)identifier
  116. handle:(YMTimerChangeBlock)handle {
  117. [self initTimerForForTime:time identifier:identifier ForIsDisk:NO unit:-1 handle:handle finish:nil pause:nil];
  118. }
  119. /** 添加定时器并开启计时 */
  120. + (void)addTimerForTime:(NSTimeInterval)time
  121. identifier:(NSString *)identifier
  122. handle:(YMTimerChangeBlock)handle
  123. finish:(YMTimerFinishBlock)finishBlock
  124. pause:(YMTimerPauseBlock)pauseBlock {
  125. [self initTimerForForTime:time identifier:identifier ForIsDisk:NO unit:-1 handle:handle finish:finishBlock pause:finishBlock];
  126. }
  127. /** 添加定时器并开启计时 */
  128. + (void)addDiskTimerForTime:(NSTimeInterval)time
  129. identifier:(NSString *)identifier
  130. handle:(YMTimerChangeBlock)handle {
  131. [self initTimerForForTime:time identifier:identifier ForIsDisk:YES unit:-1 handle:handle finish:nil pause:nil];
  132. }
  133. /** 添加定时器并开启计时 */
  134. + (void)addDiskTimerForTime:(NSTimeInterval)time
  135. identifier:(NSString *)identifier
  136. handle:(YMTimerChangeBlock)handle
  137. finish:(YMTimerFinishBlock)finishBlock
  138. pause:(YMTimerPauseBlock)pauseBlock {
  139. [self initTimerForForTime:time identifier:identifier ForIsDisk:YES unit:-1 handle:handle finish:finishBlock pause:pauseBlock];
  140. }
  141. /** 添加定时器并开启计时 */
  142. + (void)addMinuteTimerForTime:(NSTimeInterval)time handle:(YMTimerChangeBlock)handle {
  143. [self initTimerForForTime:time identifier:nil ForIsDisk:NO unit:1000 handle:handle finish:nil pause:nil];
  144. }
  145. /** 添加定时器并开启计时 */
  146. + (void)addMinuteTimerForTime:(NSTimeInterval)time
  147. identifier:(NSString *)identifier
  148. handle:(YMTimerChangeBlock)handle {
  149. [self initTimerForForTime:time identifier:identifier ForIsDisk:NO unit:1000 handle:handle finish:nil pause:nil];
  150. }
  151. /** 添加定时器并开启计时 */
  152. + (void)addMinuteTimerForTime:(NSTimeInterval)time
  153. identifier:(NSString *)identifier
  154. handle:(YMTimerChangeBlock)handle
  155. finish:(YMTimerFinishBlock)finishBlock
  156. pause:(YMTimerPauseBlock)pauseBlock {
  157. [self initTimerForForTime:time identifier:identifier ForIsDisk:NO unit:1000 handle:handle finish:finishBlock pause:finishBlock];
  158. }
  159. /** 添加定时器并开启计时 */
  160. + (void)addDiskMinuteTimerForTime:(NSTimeInterval)time
  161. identifier:(NSString *)identifier
  162. handle:(YMTimerChangeBlock)handle
  163. finish:(YMTimerFinishBlock)finishBlock
  164. pause:(YMTimerPauseBlock)pauseBlock {
  165. [self initTimerForForTime:time identifier:identifier ForIsDisk:YES unit:1000 handle:handle finish:finishBlock pause:pauseBlock];
  166. }
  167. //总初始化入口
  168. + (void)initTimerForForTime:(NSTimeInterval)time
  169. identifier:(NSString *)identifier
  170. ForIsDisk:(BOOL)isDisk
  171. unit:(NSTimeInterval)unit
  172. handle:(YMTimerChangeBlock)handle
  173. finish:(YMTimerFinishBlock)finishBlock
  174. pause:(YMTimerPauseBlock)pauseBlock {
  175. if (identifier.length<=0) {
  176. YMPopupViewTimerModel *model = [YMPopupViewTimerModel timeInterval:time];
  177. model.isDisk = isDisk;
  178. model.identifier = [NSString stringWithFormat:@"%p",model];
  179. model.unit = unit;
  180. model.handleBlock = handle;
  181. model.finishBlock = finishBlock;
  182. model.pauseBlock = pauseBlock;
  183. [YMTimerM().timerMdic setObject:model forKey:model.identifier];
  184. if (model.handleBlock) {
  185. NSInteger totalSeconds = model.time/1000.0;
  186. NSString *days = [NSString stringWithFormat:@"%zd", totalSeconds/60/60/24];
  187. NSString *hours = [NSString stringWithFormat:@"%zd", totalSeconds/60/60%24];
  188. NSString *minute = [NSString stringWithFormat:@"%zd", (totalSeconds/60)%60];
  189. NSString *second = [NSString stringWithFormat:@"%zd", totalSeconds%60];
  190. CGFloat sss = ((NSInteger)(model.time))%1000/10;
  191. NSString *ss = [NSString stringWithFormat:@"%.lf", sss];
  192. if (hours.integerValue < 10) {
  193. hours = [NSString stringWithFormat:@"0%@", hours];
  194. }
  195. if (minute.integerValue < 10) {
  196. minute = [NSString stringWithFormat:@"0%@", minute];
  197. }
  198. if (second.integerValue < 10) {
  199. second = [NSString stringWithFormat:@"0%@", second];
  200. }
  201. if (ss.integerValue < 10) {
  202. ss = [NSString stringWithFormat:@"0%@", ss];
  203. }
  204. model.handleBlock(days,hours,minute,second,ss);
  205. }
  206. // 发出通知
  207. if (model.NFType != YMTimerSecondChangeNFTypeNone) {
  208. [[NSNotificationCenter defaultCenter] postNotificationName:model.NFName object:nil userInfo:nil];
  209. }
  210. if (model.isDisk) {
  211. [self savaForTimerModel:model];
  212. }
  213. [self initTimer];
  214. return;
  215. }
  216. BOOL isTempDisk = [YMTimer timerIsExistInDiskForIdentifier:identifier];//磁盘有任务
  217. BOOL isRAM = YMTimerM().timerMdic[identifier]?YES:NO;//内存有任务
  218. if (!isRAM && !isTempDisk) {//新任务
  219. YMPopupViewTimerModel *model = [YMPopupViewTimerModel timeInterval:time];
  220. model.handleBlock = handle;
  221. model.isDisk = isDisk;
  222. model.identifier = identifier;
  223. model.unit = unit;
  224. model.finishBlock = finishBlock;
  225. model.pauseBlock = pauseBlock;
  226. [YMTimerM().timerMdic setObject:model forKey:identifier];
  227. if (model.handleBlock) {
  228. NSInteger totalSeconds = model.time/1000.0;
  229. NSString *days = [NSString stringWithFormat:@"%zd", totalSeconds/60/60/24];
  230. NSString *hours = [NSString stringWithFormat:@"%zd", totalSeconds/60/60%24];
  231. NSString *minute = [NSString stringWithFormat:@"%zd", (totalSeconds/60)%60];
  232. NSString *second = [NSString stringWithFormat:@"%zd", totalSeconds%60];
  233. CGFloat sss = ((NSInteger)(model.time))%1000/10;
  234. NSString *ss = [NSString stringWithFormat:@"%.lf", sss];
  235. if (hours.integerValue < 10) {
  236. hours = [NSString stringWithFormat:@"0%@", hours];
  237. }
  238. if (minute.integerValue < 10) {
  239. minute = [NSString stringWithFormat:@"0%@", minute];
  240. }
  241. if (second.integerValue < 10) {
  242. second = [NSString stringWithFormat:@"0%@", second];
  243. }
  244. if (ss.integerValue < 10) {
  245. ss = [NSString stringWithFormat:@"0%@", ss];
  246. }
  247. if (model.isDisk) {
  248. [self savaForTimerModel:model];
  249. }
  250. model.handleBlock(days,hours,minute,second,ss);
  251. }
  252. // 发出通知
  253. if (model.NFType != YMTimerSecondChangeNFTypeNone) {
  254. [[NSNotificationCenter defaultCenter] postNotificationName:model.NFName object:nil userInfo:nil];
  255. }
  256. [self initTimer];
  257. }
  258. if (isRAM && !isTempDisk) {//内存任务
  259. YMPopupViewTimerModel *model = YMTimerM().timerMdic[identifier];
  260. model.isPause = NO;
  261. model.handleBlock = handle;
  262. model.isDisk = isDisk;
  263. model.finishBlock = finishBlock;
  264. model.pauseBlock = pauseBlock;
  265. if (model.isDisk) {
  266. [self savaForTimerModel:model];
  267. }
  268. // [self initTimer];
  269. }
  270. if (!isRAM && isTempDisk) {//硬盘的任务
  271. YMPopupViewTimerModel *model = [YMTimer getTimerModelForIdentifier:identifier];
  272. if (isDisk == NO) {
  273. [YMTimer deleteForIdentifier:identifier];
  274. }
  275. model.isPause = NO;
  276. model.isDisk = isDisk;
  277. model.handleBlock = handle;
  278. model.finishBlock = finishBlock;
  279. model.pauseBlock = pauseBlock;
  280. [YMTimerM().timerMdic setObject:model forKey:identifier];
  281. if (model.handleBlock) {
  282. NSInteger totalSeconds = model.time/1000.0;
  283. NSString *days = [NSString stringWithFormat:@"%zd", totalSeconds/60/60/24];
  284. NSString *hours = [NSString stringWithFormat:@"%zd", totalSeconds/60/60%24];
  285. NSString *minute = [NSString stringWithFormat:@"%zd", (totalSeconds/60)%60];
  286. NSString *second = [NSString stringWithFormat:@"%zd", totalSeconds%60];
  287. CGFloat sss = ((NSInteger)(model.time))%1000/10;
  288. NSString *ss = [NSString stringWithFormat:@"%.lf", sss];
  289. if (hours.integerValue < 10) {
  290. hours = [NSString stringWithFormat:@"0%@", hours];
  291. }
  292. if (minute.integerValue < 10) {
  293. minute = [NSString stringWithFormat:@"0%@", minute];
  294. }
  295. if (second.integerValue < 10) {
  296. second = [NSString stringWithFormat:@"0%@", second];
  297. }
  298. if (ss.integerValue < 10) {
  299. ss = [NSString stringWithFormat:@"0%@", ss];
  300. }
  301. model.handleBlock(days,hours,minute,second,ss);
  302. }
  303. // 发出通知
  304. if (model.NFType != YMTimerSecondChangeNFTypeNone) {
  305. [[NSNotificationCenter defaultCenter] postNotificationName:model.NFName object:nil userInfo:nil];
  306. }
  307. if (model.isDisk) {
  308. [self savaForTimerModel:model];
  309. }
  310. [self initTimer];
  311. }
  312. if (isRAM && isTempDisk) {//硬盘的任务
  313. YMPopupViewTimerModel *model = [YMTimer getTimerModelForIdentifier:identifier];
  314. model.isPause = NO;
  315. if (isDisk == NO) {
  316. [YMTimer deleteForIdentifier:identifier];
  317. }
  318. model.isDisk = isDisk;
  319. model.handleBlock = handle;
  320. model.finishBlock = finishBlock;
  321. model.pauseBlock = pauseBlock;
  322. [YMTimerM().timerMdic setObject:model forKey:identifier];
  323. if (model.handleBlock) {
  324. NSInteger totalSeconds = model.time/1000.0;
  325. NSString *days = [NSString stringWithFormat:@"%zd", totalSeconds/60/60/24];
  326. NSString *hours = [NSString stringWithFormat:@"%zd", totalSeconds/60/60%24];
  327. NSString *minute = [NSString stringWithFormat:@"%zd", (totalSeconds/60)%60];
  328. NSString *second = [NSString stringWithFormat:@"%zd", totalSeconds%60];
  329. CGFloat sss = ((NSInteger)(model.time))%1000/10;
  330. NSString *ss = [NSString stringWithFormat:@"%.lf", sss];
  331. if (hours.integerValue < 10) {
  332. hours = [NSString stringWithFormat:@"0%@", hours];
  333. }
  334. if (minute.integerValue < 10) {
  335. minute = [NSString stringWithFormat:@"0%@", minute];
  336. }
  337. if (second.integerValue < 10) {
  338. second = [NSString stringWithFormat:@"0%@", second];
  339. }
  340. if (ss.integerValue < 10) {
  341. ss = [NSString stringWithFormat:@"0%@", ss];
  342. }
  343. model.handleBlock(days,hours,minute,second,ss);
  344. }
  345. // 发出通知
  346. if (model.NFType != YMTimerSecondChangeNFTypeNone) {
  347. [[NSNotificationCenter defaultCenter] postNotificationName:model.NFName object:nil userInfo:nil];
  348. }
  349. if (model.isDisk) {
  350. [self savaForTimerModel:model];
  351. }
  352. // [self initTimer];
  353. }
  354. }
  355. + (NSTimeInterval)getTimeIntervalForIdentifier:(NSString *)identifier {
  356. if (identifier.length<=0) {
  357. return 0.0;
  358. }
  359. BOOL isTempDisk = [YMTimer timerIsExistInDiskForIdentifier:identifier];//磁盘有任务
  360. BOOL isRAM = YMTimerM().timerMdic[identifier]?YES:NO;//内存有任务
  361. if (isTempDisk) {
  362. YMPopupViewTimerModel *model = [YMTimer loadTimerForIdentifier:identifier];
  363. return model.originalTime - model.time;
  364. }else if (isRAM) {
  365. YMPopupViewTimerModel *model = YMTimerM().timerMdic[identifier];
  366. return model.originalTime - model.time;
  367. }else {
  368. NSLog(@"找不到计时任务");
  369. return 0.0;
  370. }
  371. }
  372. + (BOOL)pauseTimerForIdentifier:(NSString *)identifier {
  373. if (identifier.length<=0) {
  374. NSLog(@"计时器标识不能为空");
  375. return NO;
  376. }
  377. YMPopupViewTimerModel *model = YMTimerM().timerMdic[identifier];
  378. if (model) {
  379. model.isPause = YES;
  380. if (model.pauseBlock) { model.pauseBlock(model.identifier); }
  381. return YES;
  382. }else {
  383. NSLog(@"找不到计时器任务");
  384. return NO;
  385. }
  386. }
  387. + (void)pauseAllTimer {
  388. [YMTimerM().timerMdic enumerateKeysAndObjectsUsingBlock:^(NSString *key, YMPopupViewTimerModel *obj, BOOL *stop) {
  389. obj.isPause = YES;
  390. if (obj.pauseBlock) { obj.pauseBlock(obj.identifier); }
  391. }];
  392. }
  393. + (BOOL)restartTimerForIdentifier:(NSString *)identifier {
  394. if (identifier.length<=0) {
  395. NSLog(@"计时器标识不能为空");
  396. return NO;
  397. }
  398. //只有内存任务才能重启, 硬盘任务只能调用addTimer系列方法重启
  399. BOOL isRAM = YMTimerM().timerMdic[identifier]?YES:NO;//内存有任务
  400. if (isRAM) {
  401. YMPopupViewTimerModel *model = YMTimerM().timerMdic[identifier];
  402. model.isPause = NO;
  403. return YES;
  404. }else {
  405. NSLog(@"找不到计时器任务");
  406. return NO;
  407. }
  408. }
  409. + (void)restartAllTimer {
  410. if (YMTimerM().timerMdic.count<=0) {
  411. return;
  412. }
  413. [YMTimerM().timerMdic enumerateKeysAndObjectsUsingBlock:^(NSString *key, YMPopupViewTimerModel *obj, BOOL *stop) {
  414. obj.isPause = NO;
  415. }];
  416. }
  417. + (BOOL)resetTimerForIdentifier:(NSString *)identifier {
  418. if (identifier.length<=0) {
  419. NSLog(@"计时器标识不能为空");
  420. return NO;
  421. }
  422. //只有内存任务才能重启, 硬盘任务只能调用addTimer系列方法重启
  423. BOOL isRAM = YMTimerM().timerMdic[identifier]?YES:NO;//内存有任务
  424. if (isRAM) {
  425. YMPopupViewTimerModel *model = YMTimerM().timerMdic[identifier];
  426. model.isPause = NO;
  427. model.time = model.originalTime;
  428. if (model.handleBlock) {
  429. NSInteger totalSeconds = model.time/1000.0;
  430. NSString *days = [NSString stringWithFormat:@"%zd", totalSeconds/60/60/24];
  431. NSString *hours = [NSString stringWithFormat:@"%zd", totalSeconds/60/60%24];
  432. NSString *minute = [NSString stringWithFormat:@"%zd", (totalSeconds/60)%60];
  433. NSString *second = [NSString stringWithFormat:@"%zd", totalSeconds%60];
  434. CGFloat sss = ((NSInteger)(model.time))%1000/10;
  435. NSString *ss = [NSString stringWithFormat:@"%.lf", sss];
  436. if (hours.integerValue < 10) {
  437. hours = [NSString stringWithFormat:@"0%@", hours];
  438. }
  439. if (minute.integerValue < 10) {
  440. minute = [NSString stringWithFormat:@"0%@", minute];
  441. }
  442. if (second.integerValue < 10) {
  443. second = [NSString stringWithFormat:@"0%@", second];
  444. }
  445. if (ss.integerValue < 10) {
  446. ss = [NSString stringWithFormat:@"0%@", ss];
  447. }
  448. model.handleBlock(days,hours,minute,second,ss);
  449. }
  450. return YES;
  451. }else {
  452. NSLog(@"找不到计时器任务");
  453. return NO;
  454. }
  455. }
  456. + (void)resetAllTimer {
  457. if (YMTimerM().timerMdic.count<=0) {
  458. return;
  459. }
  460. [YMTimerM().timerMdic enumerateKeysAndObjectsUsingBlock:^(NSString *key, YMPopupViewTimerModel *obj, BOOL *stop) {
  461. obj.isPause = NO;
  462. obj.time = obj.originalTime;
  463. if (obj.handleBlock) {
  464. NSInteger totalSeconds = obj.time/1000.0;
  465. NSString *days = [NSString stringWithFormat:@"%zd", totalSeconds/60/60/24];
  466. NSString *hours = [NSString stringWithFormat:@"%zd", totalSeconds/60/60%24];
  467. NSString *minute = [NSString stringWithFormat:@"%zd", (totalSeconds/60)%60];
  468. NSString *second = [NSString stringWithFormat:@"%zd", totalSeconds%60];
  469. CGFloat sss = ((NSInteger)(obj.time))%1000/10;
  470. NSString *ss = [NSString stringWithFormat:@"%.lf", sss];
  471. if (hours.integerValue < 10) {
  472. hours = [NSString stringWithFormat:@"0%@", hours];
  473. }
  474. if (minute.integerValue < 10) {
  475. minute = [NSString stringWithFormat:@"0%@", minute];
  476. }
  477. if (second.integerValue < 10) {
  478. second = [NSString stringWithFormat:@"0%@", second];
  479. }
  480. if (ss.integerValue < 10) {
  481. ss = [NSString stringWithFormat:@"0%@", ss];
  482. }
  483. obj.handleBlock(days,hours,minute,second,ss);
  484. }
  485. }];
  486. }
  487. + (BOOL)removeTimerForIdentifier:(NSString *)identifier {
  488. if (identifier.length<=0) {
  489. NSLog(@"计时器标识不能为空");
  490. return NO;
  491. }
  492. [YMTimerM().timerMdic removeObjectForKey:identifier];
  493. if (YMTimerM().timerMdic.count<=0) {//如果没有计时任务了 就销毁计时器
  494. [YMTimerM().showTimer invalidate];
  495. YMTimerM().showTimer = nil;
  496. }
  497. return YES;
  498. }
  499. + (void)removeAllTimer {
  500. [YMTimerM().timerMdic removeAllObjects];
  501. [YMTimerM().showTimer invalidate];
  502. YMTimerM().showTimer = nil;
  503. }
  504. /** increase YES: 递增 NO: 递减 */
  505. + (void)initTimer {
  506. if (YMTimerM().showTimer) {
  507. return;
  508. }
  509. NSTimer *timer = [NSTimer timerWithTimeInterval:0.01f target:YMTimerM() selector:@selector(timerChange) userInfo:nil repeats:YES];
  510. [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
  511. YMTimerM().showTimer = timer;
  512. }
  513. - (void)timerChange {
  514. // 时间差+
  515. [YMTimerM().timerMdic enumerateKeysAndObjectsUsingBlock:^(NSString *key, YMPopupViewTimerModel *obj, BOOL *stop) {
  516. if (!obj.isPause) {
  517. obj.time = obj.time-10.0;
  518. if (obj.unit>-1) {
  519. obj.unit = obj.unit-10.0;
  520. }
  521. if (obj.time<0) {//计时结束
  522. obj.time = 0;
  523. obj.isPause = YES;
  524. }
  525. NSInteger totalSeconds = obj.time/1000.0;
  526. NSString *days = [NSString stringWithFormat:@"%zd", totalSeconds/60/60/24];
  527. NSString *hours = [NSString stringWithFormat:@"%zd", totalSeconds/60/60%24];
  528. NSString *minute = [NSString stringWithFormat:@"%zd", (totalSeconds/60)%60];
  529. NSString *second = [NSString stringWithFormat:@"%zd", totalSeconds%60];
  530. CGFloat sss = ((NSInteger)(obj.time))%1000/10;
  531. NSString *ms = [NSString stringWithFormat:@"%.lf", sss];
  532. if (hours.integerValue < 10) {
  533. hours = [NSString stringWithFormat:@"0%@", hours];
  534. }
  535. if (minute.integerValue < 10) {
  536. minute = [NSString stringWithFormat:@"0%@", minute];
  537. }
  538. if (second.integerValue < 10) {
  539. second = [NSString stringWithFormat:@"0%@", second];
  540. }
  541. if (ms.integerValue < 10) {
  542. ms = [NSString stringWithFormat:@"0%@", ms];
  543. }
  544. if (obj.unit<=-1) {
  545. if (obj.handleBlock) {obj.handleBlock(days,hours,minute,second,ms);}
  546. if (obj.NFType == YMTimerSecondChangeNFTypeMilliSecond) {
  547. // 发出通知
  548. [[NSNotificationCenter defaultCenter] postNotificationName:obj.NFName object:nil userInfo:nil];
  549. }
  550. }else if (obj.unit == 0) {
  551. if (obj.handleBlock) {obj.handleBlock(days,hours,minute,second,ms);}
  552. obj.unit = 1000;
  553. if (obj.NFType == YMTimerSecondChangeNFTypeSecond) {
  554. // 发出通知
  555. [[NSNotificationCenter defaultCenter] postNotificationName:obj.NFName object:nil userInfo:nil];
  556. }
  557. }
  558. if (obj.isDisk) {
  559. [YMTimer savaForTimerModel:obj];
  560. }
  561. if (obj.time<=0) {//计时器计时完毕自动移除计时任务
  562. if (obj.finishBlock) { obj.finishBlock(obj.identifier); }
  563. [YMTimerM().timerMdic removeObjectForKey:obj.identifier];
  564. [YMTimer deleteForIdentifier:obj.identifier];
  565. }
  566. }
  567. }];
  568. }
  569. - (NSMutableDictionary<NSString *,YMPopupViewTimerModel *> *)timerMdic {
  570. if(_timerMdic) return _timerMdic;
  571. _timerMdic = [NSMutableDictionary dictionary];
  572. return _timerMdic;
  573. }
  574. #pragma mark - ***** other *****
  575. + (BOOL)timerIsExistInDiskForIdentifier:(NSString *)identifier {
  576. NSString *filePath = YMPopupViewTimerPath(identifier);
  577. BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
  578. return isExist;
  579. }
  580. /** 格式化时间 */
  581. + (void)formatDateForTime:(NSTimeInterval)time handle:(YMTimerChangeBlock)handle {
  582. if (handle) {
  583. NSInteger totalSeconds = time/1000.0;
  584. NSString *days = [NSString stringWithFormat:@"%zd", totalSeconds/60/60/24];
  585. NSString *hours = [NSString stringWithFormat:@"%zd", totalSeconds/60/60%24];
  586. NSString *minute = [NSString stringWithFormat:@"%zd", (totalSeconds/60)%60];
  587. NSString *second = [NSString stringWithFormat:@"%zd", totalSeconds%60];
  588. CGFloat sss = ((NSInteger)(time))%1000/10;
  589. NSString *ms = [NSString stringWithFormat:@"%.lf", sss];
  590. if (hours.integerValue < 10) {
  591. hours = [NSString stringWithFormat:@"0%@", hours];
  592. }
  593. if (minute.integerValue < 10) {
  594. minute = [NSString stringWithFormat:@"0%@", minute];
  595. }
  596. if (second.integerValue < 10) {
  597. second = [NSString stringWithFormat:@"0%@", second];
  598. }
  599. if (ms.integerValue < 10) {
  600. ms = [NSString stringWithFormat:@"0%@", ms];
  601. }
  602. handle(days,hours,minute,second,ms);
  603. }
  604. }
  605. + (BOOL)savaForTimerModel:(YMPopupViewTimerModel *)model {
  606. NSString *filePath = YMPopupViewTimerPath(model.identifier);
  607. return [NSKeyedArchiver archiveRootObject:model toFile:filePath];
  608. }
  609. + (YMPopupViewTimerModel *)loadTimerForIdentifier:(NSString *)identifier{
  610. NSString *filePath = YMPopupViewTimerPath(identifier);
  611. return [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
  612. }
  613. + (BOOL)deleteForIdentifier:(NSString *)identifier {
  614. NSString *filePath = YMPopupViewTimerPath(identifier);
  615. NSFileManager* fileManager = [NSFileManager defaultManager];
  616. BOOL isExist = [fileManager fileExistsAtPath:filePath];
  617. if (isExist) {
  618. return [fileManager removeItemAtPath:filePath error:nil];
  619. }
  620. return NO;
  621. }
  622. + (YMPopupViewTimerModel *)getTimerModelForIdentifier:(NSString *)identifier {
  623. if (identifier.length<=0) {
  624. return nil;
  625. }
  626. YMPopupViewTimerModel *model = [YMTimer loadTimerForIdentifier:identifier];
  627. return model;
  628. }
  629. @end