美文网首页
iOS 高效定时器

iOS 高效定时器

作者: 坤哥爱卿 | 来源:发表于2019-11-06 14:48 被阅读0次
    1. 中心化管理NSTimer定时器
    2. CADisplayLink
    3. GCD
    

    一、中心化管理NSTimer定时器

    日常使用中如果我们将NSTimer定时器作为视图控制器的属性,那么在这个视图控制器被释放前,将这个定时器停止,甚至置为nil,都不能使这个视图控制器被释放,原因是系统的循环池中还持有这个对象。
    如果我们不当的使用NSTimer,极易产生内存泄漏。并且在一个应用程序中激活大量的定时器十分消耗性能。我们只需要在一个定时器中添加不同的任务即可,根本不需要使用过多的定时器。用一个管理中心来统一管理定时器任务。
    创建一个定时器任务类Task
    @interface Task : NSObject
    
    -(instancetype)initWithTime:(NSUInteger)time handler:(void(^)(void))handler;
    //标志
    @property (nonatomic,strong,readonly)NSString *taskID;
    //时间单位为1/60秒
    @property (nonatomic,assign)NSUInteger time;
    //要执行的动作
    @property (nonatomic,copy) void (^event)(void);
    
    @end
    
    实现Task类的初始化方法:
    @implementation Task
    
    -(instancetype)initWithTime:(NSUInteger)time handler:(void(^)(void))handler{
        self = [super init];
        if (self) {
            self.time = time;
            self.event = handler;
            _taskID = [NSUUID UUID].UUIDString;
        }
        return self;
    }
    
    @end
    
    再创建一个单例管理类TimerManager,统一管理整个工程的定时任务
    #import "Task.h"
    
    @interface TimerManager : NSObject
    
    //单例方法
    +(instancetype)sharedManager;
    //运行定时器任务
    -(void)runTask:(Task *)task;
    //取消定时器任务
    -(void)cancelTaskWithID:(NSString *)taskID;
    
    @end
    
    @interface TimerManager ()
    
    @property (nonatomic,strong)NSMutableArray  *tasksArray;
    @property (nonatomic,strong)NSTimer *timer;
    
    @end
    
    @implementation TimerManager
    
    +(instancetype)sharedManager{
        static dispatch_once_t onceToken;
        static TimerManager *manager = nil;
        dispatch_once(&onceToken, ^{
            if (!manager) {
                manager = [[TimerManager alloc] init];
            }
        });
        return manager;
    }
    
    -(instancetype)init{
        self = [super init];
        if (self) {
            [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
        }
        return self;
    }
    
    -(void)runTask:(Task *)task{
        for (Task *t in self.tasksArray) {
            if ([t.taskID isEqualToString:task.taskID]) {
                return;
            }
        }
        [self.tasksArray addObject:task];
    }
    
    -(void)cancelTaskWithID:(NSString *)taskID{
        for (int i = (int)self.tasksArray.count-1; i >= 0; i--) {
            if ([[self.tasksArray[i] taskID] isEqualToString:taskID]) {
                [self.tasksArray removeObjectAtIndex:i];
            }
        }
    }
    
    -(NSMutableArray *)tasksArray{
        if (!_tasksArray) {
            _tasksArray = [NSMutableArray array];
        }
        return _tasksArray;
    }
    
    -(NSTimer *)timer{
        if (!_timer) {
            static int index = 0;
            _timer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 repeats:YES
                                                  block:^(NSTimer * _Nonnull timer){
                
                if (index == 59) {
                    index = 0;
                }
                for (Task *t in self.tasksArray) {
                    if (index%t.time == 0) {
                        t.event();
                    }
                }
                index++;
                
            }];
        }
        return _timer;
    }
    
    @end
    
    在工程中测试使用
    Task *t = [[Task alloc] initWithTime:30 handler:^{
            NSLog(@"event");
     } ];
        
    self.taskID = t.taskID;
    Task *t2 = [[Task alloc] initWithTime:10 handler:^{
            NSLog(@"event2");
    }];
    [[TimerManager sharedManager] runTask:t];
    [[TimerManager sharedManager] runTask:t2];
    
    //根据taskID删除任务
    [[TimerManager sharedManager] cancelTaskWithID:self.taskID];
    

    二、CADisplayLink

    CADisplayLink也是一种定时器,CADisplayLink的调用频率和设备刷新频率一致。由于它的这种特效,很多时候我们通过它来监控应用程序的帧率。
    @property (nonatomic,strong)CADisplayLink *displayLink;
    
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkLog)];
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    
    -(void)linkLog{
        static NSTimeInterval curr = 0;
        if (curr!=0) {
            NSLog(@"%f",1/(self.displayLink.timestamp-curr));
        }
        curr = self.displayLink.timestamp;
    }
    
    
    //设置CADisplayLink失效
    [self.displayLink invalidate];
    

    三、GCD方式的定时器

    平常经常会使用到的延迟处理任务方法如下:
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"hello");
        });
    
    dispatch_after的缺点是无法中途中断任务的执行。GCD也提供了可以执行定时任务的方法,并且不受RunLoop的影响。

    @property (nonatomic,strong)dispatch_source_t timer;

    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    //设置频率
    dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), 1*NSEC_PER_SEC, 0);
    //设置执行的代码块
    dispatch_source_set_event_handler(self.timer, ^{
            NSLog(@"GCD定时器");
    });
    //激活
    dispatch_resume(self.timer);
    
    //停止(取消timer)
    dispatch_source_cancel(self.timer);
    
    最后附上示例代码,觉得有帮助的顺手点个star😘

    TimerManager

    相关文章

      网友评论

          本文标题:iOS 高效定时器

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