NSTimer循环引用

NSTimer的创建方式:

+ (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;
需要手动添加到runloop

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti 
       target:(id)aTarget selector:(SEL)aSelector 
       userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
//系统默认把timer添加到当前runloop的NSDefaultRunLoopMode中

+ (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));
//需要手动添加到runloop

/// 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:  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));
//系统默认把timer添加到当前runloop的NSDefaultRunLoopMode中



/// 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;

注:生成time的方式中,以“scheduledTimer”开头的方法,系统默认把timer添加到当前runloop的
NSDefaultRunLoopMode中;而以“timerWith”和“initWith”开头的方法,需要手动添加到runloop中
参数中带有“invocation”和“block”的则可以避免循环引用;而参数有target,timer则会对target强引用;

 

  • invalidate方法会停止计时器的再次触发,并在RunLoop中将其移除。
  • invalidate方法是将NSTimer对象从RunLoop中移除的唯一方法。
  • 调用invalidate方法会删除RunLoop对NSTimer的强引用,以及NSTimer对target和userInfo的强引用!

NSTimer循环引用的示意图:

即使target参数使用weak修饰,timer仍然会对target强引用;

timer循环引用示意图
标题

 

解决循环引用问题的方法:

方法一:使用系统的invalidate,废弃NSTimer对象,并置空;

方法二:给NSTimer新增category ,并预留block接口解决;

@implementation NSTimer (KT)
+ (NSTimer *)kt_scheduledTimeWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats{
    return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(kt_blockInvoke:) userInfo:[block copy] repeats:repeats];
}
+ (void)kt_blockInvoke:(NSTimer *)timer{
    void (^block)(void) = timer.userInfo;
    if(block){ block();}
}
@end
//使用:
__weak KTVC * weakSelf = self;
[NSTimer kt_scheduledTimeWithTimeInterval:2.0 block:^{/*weakSelf something*/} repeats:YES];
//timer仍然需要调用invalidate,并置nil

方法三:使用GCD,自定义定时器;/*void dispatch_source_set_event_handler(dispatch_source_t source,dispatch_block_t _Nullable handler);*/

方法四:使用代理NSProxy(runtime消息转发);

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值