iOS 定时器

149 阅读1分钟
  • CADisplayLink 和 NSTimer 的注意点
@property(nonatomic,strong)CADisplayLink *link;
@property(nonatomic,strong)NSTimer *timer;
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkAction)];
[self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:NULL repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
-(void)linkAction
{
    NSLog(@"%s",__FUNCTION__);
}

-(void)timerAction
{
    NSLog(@"%s",__FUNCTION__);
}

-(void)dealloc
{
    NSLog(@"%s",__FUNCTION__);
    [self.link invalidate];
    self.link = nil;
    [self.timer invalidate];
    self.timer = nil;
}

在控制器中定时器并没有销毁,viewcontroller最终没有走dealloc方法

  • NSTimer 使用block的形式可以没有以上问题
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
    [weakSelf timerAction];
}];
  • 写一个中间类,让self.timer和self.link弱引用self
@interface CProxy : NSProxy

@property(nonatomic,weak)id target;
+(instancetype)proxyWithTarget:(id)target;
@end
#import "CProxy.h"

@implementation CProxy

+ (instancetype)proxyWithTarget:(id)target
{
    CProxy *proxy = [CProxy alloc];
    proxy.target = target;
    return proxy;
}

// 消息转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation invokeWithTarget:self.target];
}
@end
  • 即可解决问题
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[CProxy proxyWithTarget:self] selector:@selector(timerAction) userInfo:NULL repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];

NSTimer 不准时,所以最好用GCD

  • 使用强引用保留定时器对象
@property(nonatomic,strong)dispatch_source_t timer; 
// 设置队列
dispatch_queue_t queue = dispatch_get_main_queue(); // 主线程
dispatch_queue_t queue = dispatch_queue_create("time", DISPATCH_QUEUE_SERIAL); // 并发队列
// 设置时间
double start = 2.0; // 2秒后开始执行
double interval = 1.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 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
    NSLog(@"打印 - %@",[NSThread currentThread]);
});
dispatch_resume(timer);

self.timer = timer;
  • 取消定时器
dispatch_source_cancel(self.timer); // 取消定时器