OC经验-定时器

OC经验-定时器开启后定时器的调用频率跟屏幕刷新频率一样,依赖runloop不精准。 依赖runloop不精准。 CADisplayLink、NSTimer会对target产生强引用,如果target有对它们产生强引用,那么就会引发循环引用。 通过上面我们发现CADisplayLink、NST…

CADisplayLink

开启定时器

self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkTest)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

结束定时器

[self.displayLink invalidate];

开启后定时器的调用频率跟屏幕刷新频率一样,依赖runloop不精准。

NSTimer

开启定时器

//开启1
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(timerTest) userInfo:nil repeats:YES];
//开启2
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        
}];
//开启3
self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
    
//开启4
self.timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        
}];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];

依赖runloop不精准。

结束定时器

[self.timer invalidate];

使用scheduledTimerWithTimeInterval创建的timer会被添加到当前线程的runloop的NSDefaultRunLoopMode模式下

  • CADisplayLink、NSTimer会对target产生强引用,如果target有对它们产生强引用,那么就会引发循环引用。

  • 解决方法

    • 使用block 这种只能用于timer
    __weak typeof(self) weakSelf = self;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
          __strong typeof(self) strongSelf = weakSelf;
          [strongSelf timeTest];
    }];
    
    • 使用代理对象 OC经验-定时器
    MyProxy2 *proxy = [MyProxy2 proxyWithTarget:self];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(test) userInfo:nil repeats:YES];
    
    @interface MyProxy : NSObject
    +(instancetype)proxyWithTarget:(id)target;
    @property(nonatomic,weak)id target;
    @end
    
    @implementation MyProxy
    +(instancetype)proxyWithTarget:(id)target{
      MyProxy *proxy = [[MyProxy alloc] init];
      proxy.target = target;
      return proxy;
    }
    
    -(id)forwardingTargetForSelector:(SEL)aSelector{
      return self.target;
    }
    @end
    
    @interface MyProxy2 : NSProxy
    +(instancetype)proxyWithTarget:(id)target;
    @property(nonatomic,weak)id target;
    @end
    
    @implementation MyProxy2
    +(instancetype)proxyWithTarget:(id)target{
        MyProxy2 *proxy = [MyProxy2 alloc];
        proxy.target = target;
        return proxy;
    }
    
    - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
        return [self.target methodSignatureForSelector:sel];
    }
    
    - (void)forwardInvocation:(NSInvocation *)invocation{
        [invocation invokeWithTarget:self.target];
    }
    @end
    

NSProxy是专门用来做转发的类,效率更高,没有方法查找阶段,直接进入methodSignatureForSelector转发阶段。

GCD定时器

通过上面我们发现CADisplayLink、NSTimer不精准,要对计时器要求精准就得用到GCD. 开启定时器

-(void)test{
// dispatch_queue_t queue = dispatch_get_main_queue();
    //创建队列
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    //创建计时器
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    //一定要用强引用保留住timer 要不启动不了
    self.timer = timer;
    //开始时间 可以去设置
    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 3.0 * NSEC_PER_SEC);
    //设置开始时间,和间隔时间
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0);
    //通过block回调
// dispatch_source_set_event_handler(timer, ^{
// NSLog(@"aa");
// });
    //通过函数回调
    dispatch_source_set_event_handler_f(timer,timerFire);
    //启动定时器
    dispatch_resume(timer);
}
void timerFire(void *param){
    NSLog(@"bb,%@",[NSThread currentThread]);
}

结束定时器

dispatch_source_cancel(self.timer);

今天的文章OC经验-定时器分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23323.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注