NSTimer的使用很方便也很简单,但使用时需要把创建的timer定义成一个成语变量或属性持有,不然调用的block会一直执行,及时当前对象已经销毁了,block还会执行
- (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>
现在特意封装了一下NSTimer,让在开发或调试时随意使用NSTimer而不用专门定义一个变量来持有timer,同时随着使用timer的对象销毁后,timer也自动销毁,以提高开发效率
基本原理如下:
1、虽然表面使用者没有专门定义一个变量来持有timer,但实际上通过runtime的方式来持有该timer
2、由于使用runtime的objc_getAssociatedObject/objc_setAssociatedObject的方式持有一个间接变量,所以间接变量会随着调用timer的这个宿主销毁而销毁,在销毁时自动同事销毁timer
3、添加一个使用timer时常用的计数器传递出来,这样方便timer的使用
4、自定义的ZQQTimer实现了invalidate方法,可以根据业务逻辑需要手动代码关闭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);
}
// -----防止数字越界 快捷键为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
测试代码如下:
- (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) { // 可以手动取消timer的执行
[timer invalidate];
}
}];
[self startTimerWithBlock:^(ZQQTimer * timer, NSInteger repeatCount) {
}];
}
- (void)dealloc
{
NSLog(@"delloc %s",__FUNCTION__);
}
这上面的代码还用到了NSObject+ZQQBindData这个分类,这个之前博客里介绍过,主要利用下标语法,让任何NSObject都用有字典一样简便的读取变量的的功能,减少很多定义变量的麻烦