美文网首页
简化NSTimer的使用

简化NSTimer的使用

作者: 独孤流 | 来源:发表于2017-05-22 15:57 被阅读65次

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都用有字典一样简便的读取变量的的功能,减少很多定义变量的麻烦

完整demo

相关文章

  • 简化NSTimer的使用

    NSTimer的使用很方便也很简单,但使用时需要把创建的timer定义成一个成语变量或属性持有,不然调用的bloc...

  • NSTimer的循环引用

    NSTimer基本使用 NSTimer与RunLoop NSTimer 循环引用的问题 如何在子线程使用NSTim...

  • iOS-NSTimer-循环引用问题

    在使用NSTimer的时候,NSTimer会生成指向其使用者的引用,而其使用者如果也引用了NSTimer,那么就会...

  • NSTimer的使用

    NSTimer 的使用 为什么会写NSTimer呢? 原因很简单, 这里有坑! NSTimer 使用的顺序 创建N...

  • 倒计时实现方法两个

    方法1:使用NSTimer来实现 主要使用的是NSTimer的scheduledTimerWithTimeInte...

  • 内存管理总结

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

  • Objective-C基础-内存管理

    1、CADisplayLink、NSTimer使用 CADisplayLink、NSTimer会对target产生...

  • CADisplayLink、NSTimer使用注意

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

  • 底层-内存管理

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

  • 内存管理

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

网友评论

      本文标题:简化NSTimer的使用

      本文链接:https://www.haomeiwen.com/subject/ghzbxxtx.html