iOS底层系列之<46>--内存管理<2>定时器

1、定时器相关

看这个不错(https://www.jianshu.com/p/f641970d7439)

(a) 上一篇文章介绍了定时器相关内容,CADisplayLink 和NSTimer都是基于Runloop的定时器,但是Runloop的任务过于繁重的时候,定时器就不准了!
(b)所以,在项目中,尽量使用GCD定时器会更准确。

2、GCD定时器封装

类方法调用,但是我觉得可以封装成实例方法可能会更好一点,晚点再封装一次。
JHTimer.h文件

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

//typedef (void)(^Task)(void);

@interface JHTimer : NSObject
+ (NSString *)excuteTask:(void (^)(void))task
             start:(NSTimeInterval)start
          interval:(NSTimeInterval)interval
         isRepeats:(BOOL)isRepeats
           isAsync:(BOOL)isAsync;

+ (void)cancelTimer:(NSString *)name;

+ (void)suspendTimer:(NSString *)name;

+ (void)restartTimer:(NSString *)name;
@end

NS_ASSUME_NONNULL_END

JHTimer.m文件

#import "JHTimer.h"

@implementation JHTimer

static NSMutableDictionary *timerDict;
static BOOL isStarted;
static BOOL isCanceled;
static BOOL isSuspended;
static BOOL isRestarted;
dispatch_semaphore_t semaphore;

+ (void)initialize {
    static dispatch_once_t onecToken;
    dispatch_once(&onecToken, ^{
        timerDict = [NSMutableDictionary dictionary];
        isStarted = NO;
        isCanceled = NO;
        isSuspended = NO;
        isRestarted = NO;
        semaphore = dispatch_semaphore_create(1);
    });
    
}

/**
 
 task: 任务
 start: 开始时间
 interval: 间隔时间
 isRpeats: 是否重复
 isMainQueue: 是否主线程
 
 return: 时间的标识符,开启一个定时器后,在需要的地方可以用一个标识符记录
 */
+ (NSString *)excuteTask:(void (^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval isRepeats:(BOOL)isRepeats isMainQueue:(BOOL)isMainQueue {
    if (!task || start < 0 || interval < 0) {
        return nil;
    }
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    NSString *timerName = [NSString stringWithFormat:@"%@%@",@"EFTimer_",[self __currentTimeStr]];
    
    dispatch_queue_t queue = isMainQueue ? dispatch_get_main_queue() : dispatch_get_global_queue(0, 0);
    
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, start * NSEC_PER_SEC), interval * NSEC_PER_SEC, 0);
    
    dispatch_source_set_event_handler(timer, ^{
        task();
        if (!isRepeats) {
            [self __cancelTimer:timerName];
        }
    });
    
    dispatch_resume(timer);
    
    
    timerDict[timerName] = timer;
    
    isStarted = YES;
    isCanceled = NO;
    isSuspended = NO;
    isRestarted = NO;
    
    dispatch_semaphore_signal(semaphore);
    
    return timerName;
}

/**
 根据创建的时候返回的标识符来取消定时器
 */
+ (void)cancelTimer:(NSString *)name {
    if ([timerDict objectForKey:name] == nil || isSuspended) {
        return;
    }
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_cancel([timerDict objectForKey:name]);
    [timerDict removeObjectForKey:name];
    isStarted = NO;
    isCanceled = NO;
    isSuspended = NO;
    isRestarted = NO;
    
    dispatch_semaphore_signal(semaphore);
}

// 开启状态才可以
+ (void)suspendTimer:(NSString *)name {
    if ([timerDict objectForKey:name] == nil || !isStarted || isCanceled || isSuspended) {
        return;
    }
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_suspend([timerDict objectForKey:name]);
    isStarted = YES;
    isCanceled = NO;
    isSuspended = YES;
    isRestarted = NO;
    
    dispatch_semaphore_signal(semaphore);
}

// suspend状态才可以
+ (void)restartTimer:(NSString *)name {
    if ([timerDict objectForKey:name] == nil || !isSuspended || isRestarted || isCanceled || !isStarted) {
        return;
    }
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_resume([timerDict objectForKey:name]);
    isStarted = YES;
    isCanceled = NO;
    isSuspended = NO;
    isRestarted = YES;
    
    dispatch_semaphore_signal(semaphore);
}


+ (void)__cancelTimer:(NSString *)name {
    dispatch_cancel(timerDict[name]);
    [timerDict removeObjectForKey:name];
}

//获取当前时间戳
+ (NSString *)__currentTimeStr {
    NSDate* date = [NSDate dateWithTimeIntervalSinceNow:0];//获取当前时间0秒后的时间
    NSTimeInterval time = [date timeIntervalSince1970]*1000;// *1000 是精确到毫秒,不乘就是精确到秒
    NSString *timeString = [NSString stringWithFormat:@"%.0f", time];
    return timeString;
}

@end

3、iOS程序的内存布局

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值