NSTimer 循环引用问题
使用此方法创建,会形成循环引用,即使在dealloc中调用
[self.timer invalidate]以及self.timer = nil;也是解决不了循环引用的问题。
产生循环引用原因:当前VC 持有timer,但是timer有对传入的target有强引用,以此形成循环引用。
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];
解决方法:
1.通过中间件来进行解除循环引用,使用代理对象来进行强引用timer, vc对其代理对象弱引用,以此来解决。
创建一个代理对象LProxy,
LProxy.h
@interface LProxy : NSObject
+(instancetype)proxyWithTarget:(id)target;
@property (nonatomic, weak) id target;
@end
LProxy.m
#import
@implementation LProxy
+(instancetype)proxyWithTarget:(id)target{
LProxy *p = [[LProxy alloc]init];
p.target = target;
return p;
}
//此处是为了在使用时target为当前的LProxy,但是找不到LProxy的timerTest方法出现carch,通过消息转发来实现消息的接受者为传入的target来,以此解决因找不到target的方法出现的carch
- (id)forwardingTargetForSelector:(SEL)aSelector{
return self.target;
}
@end
在使用的时候,通过代理对象的target来进行一步弱引用解决循环
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[LProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
或者LProxy直接继承NSProxy来实现消息的方法签名以及消息的转发,
LProxy.h
@interface LProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (nonatomic, weak) id target;
@end
LProxy.m
@implementation LProxy
+ (instancetype)proxyWithTarget:(id)target{
LProxy *proxy = [LProxy alloc];
proxy.target = target;
return proxy;
}
//方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
return [self.target methodSignatureForSelector:sel];
}
//将方法签名的sel转发为当前的target来进行消息转发
- (void)forwardInvocation:(NSInvocation *)invocation{
[invocation invokeWithTarget:self.target];
}
@end
2.或者直接把NSTimer的创建也放在代理对象实现,通过代理方法把时间间隔以及执行方法暴露给外界使用, 此时也能解决NSTimer循环引用问题。
3.使用下来方法类进行创建,不对其self进行强引用
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
}];
NSTimer 使用准时吗? 解决方法?
NSTimer使用不准时,因为NStimer底层是基于NSRunloop的,如果Runloop的任务过于繁重,可能会导致NSTimer不准时,可以使用GCD的定时器,因为GCD定时器不依赖于runloop,它依赖系统内核。