区块链技术博客
www.b2bchain.cn

定时器求职学习资料

D0b2wT.gif

本文介绍了定时器求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

定时器

重拾iOS.jpg

关键词:NSTimer、CADisplayLink、GCD、RunLoop

前言

  1. 开发中常用的定时器有哪些,优缺点是什么?
  2. 定时器的循环引用问题怎么解决?
  3. CADisplayLink、NSTimer是否准时?

一、NSTimer和CADisplayLink

1、NSTimer

常用api有:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;  + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;   /// Creates and returns a new NSTimer object initialized with the specified block object. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire. /// - parameter:  timeInterval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  /// Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the current run loop in the default mode. /// - parameter:  ti    The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  /// Initializes a new NSTimer object using the block as the main body of execution for the timer. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire. /// - parameter:  fireDate   The time at which the timer should first fire. /// - parameter:  interval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;  - (void)fire;

在NSTimer的初始化方法中,以scheduled开头的方法,timer默认已经添加到了当前RunLoop中(以default mode形式添加)

2、CADisplayLink

常用api有:

/* Create a new display link object for the main display. It will  * invoke the method called 'sel' on 'target', the method has the  * signature '(void)selector:(CADisplayLink *)sender'. */  + (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel;  /* Adds the receiver to the given run-loop and mode. Unless paused, it  * will fire every vsync until removed. Each object may only be added  * to a single run-loop, but it may be added in multiple modes at once.  * While added to a run-loop it will implicitly be retained. */  - (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode;  /* Removes the receiver from the given mode of the runloop. This will  * implicitly release it when removed from the last mode it has been  * registered for. */  - (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode;  /* Removes the object from all runloop modes (releasing the receiver if  * it has been implicitly retained) and releases the 'target' object. */  - (void)invalidate;

二、定时器循环引用问题的解决方案

1、使用block方式初始化NSTimer;

2、使用中间层WeakContainer;

代码示例:

新建SFWeakContainer类

// .h @interface SFWeakContainer : NSObject  - (instancetype)initWithTarget:(NSObject *)target; + (instancetype)containerWithTarget:(NSObject *)target;  @end  // .m @interface SFWeakContainer () @property (nonatomic, weak) NSObject *target; @end  @implementation SFWeakContainer  - (instancetype)initWithTarget:(NSObject *)target {     if (self = [super init]) {         self.target = target;     }     return self; } + (instancetype)containerWithTarget:(NSObject *)target {     SFWeakContainer *container = [[SFWeakContainer alloc]initWithTarget:target];     return container; }  // 备用接受者 - (id)forwardingTargetForSelector:(SEL)aSelector {     if (self.target && [self.target respondsToSelector:aSelector]) {         return self.target;     }else{         return [super forwardingTargetForSelector:aSelector];     } }  @end

测试:

- (void)viewDidLoad {     [super viewDidLoad];     self.view.backgroundColor = [UIColor whiteColor];     SFWeakContainer *weakContainer = [SFWeakContainer containerWithTarget:self];     self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakContainer selector:@selector(timerEvent:) userInfo:nil repeats:YES]; }  - (void)timerEvent:(NSTimer *)timer {     NSLog(@"定时器事件"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil;     NSLog(@"%s", __func__); }

3、NSProxy消息转发;

代码示例:

新建SFProxy

// .h @interface SFProxy : NSProxy - (instancetype)initWithTarget:(id)target; + (instancetype)proxyWithTarget:(id)target; @end  // .m @interface SFProxy () @property (nonatomic, weak) NSObject *target; @end  @implementation SFProxy - (instancetype)initWithTarget:(id)target {     _target = target;     return self; } + (instancetype)proxyWithTarget:(id)target {     return [[self alloc] initWithTarget:target]; }  // 消息转发 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{     if (self.target && [self.target respondsToSelector:aSelector]) {         return [self.target methodSignatureForSelector:aSelector];     }     return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation{     SEL aSelector = [anInvocation selector];     if (self.target && [self.target respondsToSelector:aSelector]) {         [anInvocation invokeWithTarget:self.target];     } else {         [super forwardInvocation:anInvocation];     } } @end

测试:

- (void)viewDidLoad {     [super viewDidLoad];     self.view.backgroundColor = [UIColor whiteColor];     SFProxy *proxy = [SFProxy proxyWithTarget:self];     self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(timerEvent:) userInfo:nil repeats:YES]; }  - (void)timerEvent:(NSTimer *)timer {     NSLog(@"定时器事件"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil;     NSLog(@"%s", __func__); }

具体怎么做,根据个人喜好选择,我这里有一个写好的方案:Crash防护(4)-NSTimer

三、CADisplayLink、NSTimer是否准时?

CADisplayLink、NSTimer底层都是靠RunLoop来实现的,也就是可以把它们理解成RunLoop所需要处理的事件。我们知道RunLoop可以拿来刷新UI,处理定时器(CADisplayLink、NSTimer),处理点击滑动事件等非常多的事情。这里,就需要来了解一下RunLoop是如何触发NSTimer任务的。RunLoop每循环一圈,都会处理一定的事件,会消耗一定的时间,但是具体耗时多少这个是无法确定的。

假如你开启一个timer,隔1秒触发定时器事件,RunLoop会开始累计每一圈循环的用时,当时间累计够1秒,就会触发定时器事件。你有兴趣的话,是可以在RunLoop的源码里面找到时间累加相关代码的。可以借助下图来加深理解:

定时器

如果RunLoop在某一圈任务过于繁重,就可能出现如下情况

定时器

重拾iOS.jpg

关键词:NSTimer、CADisplayLink、GCD、RunLoop

前言

  1. 开发中常用的定时器有哪些,优缺点是什么?
  2. 定时器的循环引用问题怎么解决?
  3. CADisplayLink、NSTimer是否准时?

一、NSTimer和CADisplayLink

1、NSTimer

常用api有:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;  + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;   /// Creates and returns a new NSTimer object initialized with the specified block object. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire. /// - parameter:  timeInterval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  /// Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the current run loop in the default mode. /// - parameter:  ti    The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  /// Initializes a new NSTimer object using the block as the main body of execution for the timer. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire. /// - parameter:  fireDate   The time at which the timer should first fire. /// - parameter:  interval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;  - (void)fire;

在NSTimer的初始化方法中,以scheduled开头的方法,timer默认已经添加到了当前RunLoop中(以default mode形式添加)

2、CADisplayLink

常用api有:

/* Create a new display link object for the main display. It will  * invoke the method called 'sel' on 'target', the method has the  * signature '(void)selector:(CADisplayLink *)sender'. */  + (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel;  /* Adds the receiver to the given run-loop and mode. Unless paused, it  * will fire every vsync until removed. Each object may only be added  * to a single run-loop, but it may be added in multiple modes at once.  * While added to a run-loop it will implicitly be retained. */  - (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode;  /* Removes the receiver from the given mode of the runloop. This will  * implicitly release it when removed from the last mode it has been  * registered for. */  - (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode;  /* Removes the object from all runloop modes (releasing the receiver if  * it has been implicitly retained) and releases the 'target' object. */  - (void)invalidate;

二、定时器循环引用问题的解决方案

1、使用block方式初始化NSTimer;

2、使用中间层WeakContainer;

代码示例:

新建SFWeakContainer类

// .h @interface SFWeakContainer : NSObject  - (instancetype)initWithTarget:(NSObject *)target; + (instancetype)containerWithTarget:(NSObject *)target;  @end  // .m @interface SFWeakContainer () @property (nonatomic, weak) NSObject *target; @end  @implementation SFWeakContainer  - (instancetype)initWithTarget:(NSObject *)target {     if (self = [super init]) {         self.target = target;     }     return self; } + (instancetype)containerWithTarget:(NSObject *)target {     SFWeakContainer *container = [[SFWeakContainer alloc]initWithTarget:target];     return container; }  // 备用接受者 - (id)forwardingTargetForSelector:(SEL)aSelector {     if (self.target && [self.target respondsToSelector:aSelector]) {         return self.target;     }else{         return [super forwardingTargetForSelector:aSelector];     } }  @end

测试:

- (void)viewDidLoad {     [super viewDidLoad];     self.view.backgroundColor = [UIColor whiteColor];     SFWeakContainer *weakContainer = [SFWeakContainer containerWithTarget:self];     self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakContainer selector:@selector(timerEvent:) userInfo:nil repeats:YES]; }  - (void)timerEvent:(NSTimer *)timer {     NSLog(@"定时器事件"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil;     NSLog(@"%s", __func__); }

3、NSProxy消息转发;

代码示例:

新建SFProxy

// .h @interface SFProxy : NSProxy - (instancetype)initWithTarget:(id)target; + (instancetype)proxyWithTarget:(id)target; @end  // .m @interface SFProxy () @property (nonatomic, weak) NSObject *target; @end  @implementation SFProxy - (instancetype)initWithTarget:(id)target {     _target = target;     return self; } + (instancetype)proxyWithTarget:(id)target {     return [[self alloc] initWithTarget:target]; }  // 消息转发 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{     if (self.target && [self.target respondsToSelector:aSelector]) {         return [self.target methodSignatureForSelector:aSelector];     }     return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation{     SEL aSelector = [anInvocation selector];     if (self.target && [self.target respondsToSelector:aSelector]) {         [anInvocation invokeWithTarget:self.target];     } else {         [super forwardInvocation:anInvocation];     } } @end

测试:

- (void)viewDidLoad {     [super viewDidLoad];     self.view.backgroundColor = [UIColor whiteColor];     SFProxy *proxy = [SFProxy proxyWithTarget:self];     self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(timerEvent:) userInfo:nil repeats:YES]; }  - (void)timerEvent:(NSTimer *)timer {     NSLog(@"定时器事件"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil;     NSLog(@"%s", __func__); }

具体怎么做,根据个人喜好选择,我这里有一个写好的方案:Crash防护(4)-NSTimer

三、CADisplayLink、NSTimer是否准时?

CADisplayLink、NSTimer底层都是靠RunLoop来实现的,也就是可以把它们理解成RunLoop所需要处理的事件。我们知道RunLoop可以拿来刷新UI,处理定时器(CADisplayLink、NSTimer),处理点击滑动事件等非常多的事情。这里,就需要来了解一下RunLoop是如何触发NSTimer任务的。RunLoop每循环一圈,都会处理一定的事件,会消耗一定的时间,但是具体耗时多少这个是无法确定的。

假如你开启一个timer,隔1秒触发定时器事件,RunLoop会开始累计每一圈循环的用时,当时间累计够1秒,就会触发定时器事件。你有兴趣的话,是可以在RunLoop的源码里面找到时间累加相关代码的。可以借助下图来加深理解:

定时器

如果RunLoop在某一圈任务过于繁重,就可能出现如下情况

定时器

重拾iOS.jpg

关键词:NSTimer、CADisplayLink、GCD、RunLoop

前言

  1. 开发中常用的定时器有哪些,优缺点是什么?
  2. 定时器的循环引用问题怎么解决?
  3. CADisplayLink、NSTimer是否准时?

一、NSTimer和CADisplayLink

1、NSTimer

常用api有:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;  + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;   /// Creates and returns a new NSTimer object initialized with the specified block object. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire. /// - parameter:  timeInterval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  /// Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the current run loop in the default mode. /// - parameter:  ti    The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  /// Initializes a new NSTimer object using the block as the main body of execution for the timer. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire. /// - parameter:  fireDate   The time at which the timer should first fire. /// - parameter:  interval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead /// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. /// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));  - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;  - (void)fire;

在NSTimer的初始化方法中,以scheduled开头的方法,timer默认已经添加到了当前RunLoop中(以default mode形式添加)

2、CADisplayLink

常用api有:

/* Create a new display link object for the main display. It will  * invoke the method called 'sel' on 'target', the method has the  * signature '(void)selector:(CADisplayLink *)sender'. */  + (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel;  /* Adds the receiver to the given run-loop and mode. Unless paused, it  * will fire every vsync until removed. Each object may only be added  * to a single run-loop, but it may be added in multiple modes at once.  * While added to a run-loop it will implicitly be retained. */  - (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode;  /* Removes the receiver from the given mode of the runloop. This will  * implicitly release it when removed from the last mode it has been  * registered for. */  - (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode;  /* Removes the object from all runloop modes (releasing the receiver if  * it has been implicitly retained) and releases the 'target' object. */  - (void)invalidate;

二、定时器循环引用问题的解决方案

1、使用block方式初始化NSTimer;

2、使用中间层WeakContainer;

代码示例:

新建SFWeakContainer类

// .h @interface SFWeakContainer : NSObject  - (instancetype)initWithTarget:(NSObject *)target; + (instancetype)containerWithTarget:(NSObject *)target;  @end  // .m @interface SFWeakContainer () @property (nonatomic, weak) NSObject *target; @end  @implementation SFWeakContainer  - (instancetype)initWithTarget:(NSObject *)target {     if (self = [super init]) {         self.target = target;     }     return self; } + (instancetype)containerWithTarget:(NSObject *)target {     SFWeakContainer *container = [[SFWeakContainer alloc]initWithTarget:target];     return container; }  // 备用接受者 - (id)forwardingTargetForSelector:(SEL)aSelector {     if (self.target && [self.target respondsToSelector:aSelector]) {         return self.target;     }else{         return [super forwardingTargetForSelector:aSelector];     } }  @end

测试:

- (void)viewDidLoad {     [super viewDidLoad];     self.view.backgroundColor = [UIColor whiteColor];     SFWeakContainer *weakContainer = [SFWeakContainer containerWithTarget:self];     self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakContainer selector:@selector(timerEvent:) userInfo:nil repeats:YES]; }  - (void)timerEvent:(NSTimer *)timer {     NSLog(@"定时器事件"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil;     NSLog(@"%s", __func__); }

3、NSProxy消息转发;

代码示例:

新建SFProxy

// .h @interface SFProxy : NSProxy - (instancetype)initWithTarget:(id)target; + (instancetype)proxyWithTarget:(id)target; @end  // .m @interface SFProxy () @property (nonatomic, weak) NSObject *target; @end  @implementation SFProxy - (instancetype)initWithTarget:(id)target {     _target = target;     return self; } + (instancetype)proxyWithTarget:(id)target {     return [[self alloc] initWithTarget:target]; }  // 消息转发 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{     if (self.target && [self.target respondsToSelector:aSelector]) {         return [self.target methodSignatureForSelector:aSelector];     }     return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation{     SEL aSelector = [anInvocation selector];     if (self.target && [self.target respondsToSelector:aSelector]) {         [anInvocation invokeWithTarget:self.target];     } else {         [super forwardInvocation:anInvocation];     } } @end

测试:

- (void)viewDidLoad {     [super viewDidLoad];     self.view.backgroundColor = [UIColor whiteColor];     SFProxy *proxy = [SFProxy proxyWithTarget:self];     self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(timerEvent:) userInfo:nil repeats:YES]; }  - (void)timerEvent:(NSTimer *)timer {     NSLog(@"定时器事件"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil;     NSLog(@"%s", __func__); }

具体怎么做,根据个人喜好选择,我这里有一个写好的方案:Crash防护(4)-NSTimer

三、CADisplayLink、NSTimer是否准时?

CADisplayLink、NSTimer底层都是靠RunLoop来实现的,也就是可以把它们理解成RunLoop所需要处理的事件。我们知道RunLoop可以拿来刷新UI,处理定时器(CADisplayLink、NSTimer),处理点击滑动事件等非常多的事情。这里,就需要来了解一下RunLoop是如何触发NSTimer任务的。RunLoop每循环一圈,都会处理一定的事件,会消耗一定的时间,但是具体耗时多少这个是无法确定的。

假如你开启一个timer,隔1秒触发定时器事件,RunLoop会开始累计每一圈循环的用时,当时间累计够1秒,就会触发定时器事件。你有兴趣的话,是可以在RunLoop的源码里面找到时间累加相关代码的。可以借助下图来加深理解:

定时器

如果RunLoop在某一圈任务过于繁重,就可能出现如下情况

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 定时器求职学习资料
分享到: 更多 (0)
D0b2wT.gif

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们