NSTimer的使用很方便也很簡(jiǎn)單,但使用時(shí)需要把創(chuàng)建的timer定義成一個(gè)成語(yǔ)變量或?qū)傩猿钟斜蓿蝗徽{(diào)用的block會(huì)一直執(zhí)行是晨,及時(shí)當(dāng)前對(duì)象已經(jīng)銷毀了,block還會(huì)執(zhí)行
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 80, 40, 20)];
lbl.textColor = [UIColor blackColor];
lbl.font = [UIFont systemFontOfSize:14];
lbl.backgroundColor = [UIColor redColor];
lbl.text = @"0---";
lbl.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:lbl];
__weak typeof(self) weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"weakself %@ %@",weakSelf,lbl.text);
}];
// [ZQQTimer timerWithHolder:self delay:0 TimeInterval:0 block:^(ZQQTimer *timer, NSInteger repeatCount) {
// NSLog(@"aaa %ld %@",repeatCount,timer);
// if (repeatCount == 5) {
// [timer invalidate];
// }
// }];
//
//
// [self startTimerDelay:0 timeInterval:1 block:^(ZQQTimer *timer, NSInteger repeatCount) {
// NSLog(@"%ld timer:%@",repeatCount,timer);
// lbl.text = [NSString stringWithFormat:@"%ld",repeatCount];
// }];
//
// [self startTimerWithBlock:^(ZQQTimer * timer, NSInteger repeatCount) {
//
// }];
}
- (void)dealloc
{
NSLog(@"delloc %s",__FUNCTION__);
}
<pre>
2017-05-22 15:37:42.762 YZDisplayViewControllerDemo[31145:3580555] weakself <TestZQQTimerViewController: 0x7fe4d8549b70> 0---
2017-05-22 15:37:43.763 YZDisplayViewControllerDemo[31145:3580555] weakself <TestZQQTimerViewController: 0x7fe4d8549b70> 0---
2017-05-22 15:37:44.313 YZDisplayViewControllerDemo[31145:3580555] delloc -[TestZQQTimerViewController dealloc]
2017-05-22 15:37:44.763 YZDisplayViewControllerDemo[31145:3580555] weakself (null) 0---
2017-05-22 15:37:45.763 YZDisplayViewControllerDemo[31145:3580555] weakself (null) 0---
2017-05-22 15:37:46.763 YZDisplayViewControllerDemo[31145:3580555] weakself (null) 0---
2017-05-22 15:37:47.763 YZDisplayViewControllerDemo[31145:3580555] weakself (null) 0---
</pre>
現(xiàn)在特意封裝了一下NSTimer舔箭,讓在開(kāi)發(fā)或調(diào)試時(shí)隨意使用NSTimer而不用專門(mén)定義一個(gè)變量來(lái)持有timer罩缴,同時(shí)隨著使用timer的對(duì)象銷毀后,timer也自動(dòng)銷毀层扶,以提高開(kāi)發(fā)效率
基本原理如下:
1箫章、雖然表面使用者沒(méi)有專門(mén)定義一個(gè)變量來(lái)持有timer,但實(shí)際上通過(guò)runtime的方式來(lái)持有該timer
2镜会、由于使用runtime的objc_getAssociatedObject/objc_setAssociatedObject的方式持有一個(gè)間接變量檬寂,所以間接變量會(huì)隨著調(diào)用timer的這個(gè)宿主銷毀而銷毀,在銷毀時(shí)自動(dòng)同事銷毀timer
3戳表、添加一個(gè)使用timer時(shí)常用的計(jì)數(shù)器傳遞出來(lái)桶至,這樣方便timer的使用
4、自定義的ZQQTimer實(shí)現(xiàn)了invalidate方法匾旭,可以根據(jù)業(yè)務(wù)邏輯需要手動(dòng)代碼關(guān)閉timer
具體代碼如下
ZQQTimer.h
//
// ZQQTimer.h
// zqqkit
//
// Created by liuhuan on 2017/5/22.
// Copyright ? 2017年 zqq.love All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class ZQQTimer;
typedef void(^ZQQTimerBlock)(ZQQTimer * _Nonnull timer,NSInteger repeatCount);
@interface ZQQTimer : NSObject
+ (ZQQTimer *_Nonnull)timerWithHolder:(nonnull id)holder delay:(NSTimeInterval)delay TimeInterval:(NSTimeInterval)timeInterval block:(ZQQTimerBlock _Nullable )block;
- (void)invalidate;
@property (readonly, getter=isValid) BOOL valid;
@property (nonatomic,assign) NSInteger repeatCount;
@end
ZQQTimer.m
//
// ZQQTimer.m
// ZQQKit
//
// Created by liuhuan on 2017/5/22.
// Copyright ? 2017年 zqq.love. All rights reserved.
//
#import "ZQQTimer.h"
#import "NSObject+ZQQBindData.h"
#define kSaveZQQTimerInOneHolderKey @"kSaveZQQTimerInOneHolderKey"
@interface ZQQTimer()
@property (nonatomic,copy) ZQQTimerBlock block;
@property (nonatomic,strong) NSTimer * timer;
@property (nonatomic,weak) id holder;
@property (nonatomic,assign) NSTimeInterval timeInterval;
@property (nonatomic,assign) NSTimeInterval delay;
@end
@implementation ZQQTimer
+ (ZQQTimer *)timerWithHolder:(id)holder delay:(NSTimeInterval)delay TimeInterval:(NSTimeInterval)timeInterval block:(ZQQTimerBlock)block
{
ZQQTimer *zqqTimer = [ZQQTimer new];
NSMutableDictionary *dictM = [holder valueForKey:kSaveZQQTimerInOneHolderKey defaultValue:[NSMutableDictionary dictionary]];
dictM[zqqTimer.description] = zqqTimer;
zqqTimer.block = [block copy];
zqqTimer.holder = holder;
zqqTimer.timeInterval = timeInterval;
zqqTimer.delay = delay;
[zqqTimer showTimer];
return zqqTimer;
}
- (void)showTimer
{
if (self.timeInterval == 0) {
self.timeInterval = 1;
}
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
weakSelf.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeInterval repeats:YES block:^(NSTimer * _Nonnull timer) {
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.repeatCount += 1;
if (strongSelf.block) {
strongSelf.block(strongSelf,strongSelf.repeatCount);
}
// -----防止數(shù)字越界 快捷鍵為gg
if (strongSelf.repeatCount == NSIntegerMax) {
strongSelf.repeatCount = 0;
}
}];
});
}
- (void)invalidate
{
[self.timer invalidate];
self.timer = nil;
NSMutableDictionary *dictM = self.holder[kSaveZQQTimerInOneHolderKey];
[dictM removeObjectForKey:self.description];
}
- (BOOL)isValid
{
return [self.timer isValid];
}
- (void)dealloc
{
[self.timer invalidate];
self.timer = nil;
NSLog(@"dealloc %s",__FUNCTION__);
}
@end
測(cè)試代碼如下:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 80, 40, 20)];
lbl.textColor = [UIColor blackColor];
lbl.font = [UIFont systemFontOfSize:14];
lbl.backgroundColor = [UIColor redColor];
lbl.text = @"0---";
lbl.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:lbl];
__weak typeof(self) weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"weakself %@ %@",weakSelf,lbl.text);
}];
[ZQQTimer timerWithHolder:self delay:0 TimeInterval:0 block:^(ZQQTimer *timer, NSInteger repeatCount) {
NSLog(@"aaa %ld %@",repeatCount,timer);
if (repeatCount == 5) {
[timer invalidate];
}
}];
[self startTimerDelay:0 timeInterval:1 block:^(ZQQTimer *timer, NSInteger repeatCount) {
NSLog(@"%ld timer:%@",repeatCount,timer);
lbl.text = [NSString stringWithFormat:@"%ld",repeatCount];
if (repeatCount == 5) { // 可以手動(dòng)取消timer的執(zhí)行
[timer invalidate];
}
}];
[self startTimerWithBlock:^(ZQQTimer * timer, NSInteger repeatCount) {
}];
}
- (void)dealloc
{
NSLog(@"delloc %s",__FUNCTION__);
}
這上面的代碼還用到了NSObject+ZQQBindData這個(gè)分類镣屹,這個(gè)之前博客里介紹過(guò),主要利用下標(biāo)語(yǔ)法价涝,讓任何NSObject都用有字典一樣簡(jiǎn)便的讀取變量的的功能女蜈,減少很多定義變量的麻煩