self -> Timer -> target(self), 造成循环引用
导致不会调用dealloc 方法,内存泄漏
- (void)dealloc{ [_timer invalidate]; NSLog(@"********************delloc**************8"); }
__weak typeof(self)weakself = self; _timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) { weakself.count++; NSLog(@"-------%ld",weakself.count); }];
在适当的时机调用 (达到一定条件或者 例如在- (void)viewDidDisappear:(BOOL)animated {}调用,)
[self.timer invalidate];
self.timer = nil;
// 借助runtime给对象添加消息处理的能力 _objct = [[NSObject alloc] init]; class_addMethod([_objct class], @selector(test), class_getMethodImplementation([self class], @selector(test)), "v@:"); _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(test) userInfo:@"ddd" repeats:YES];
创建一个中间类 PHJProxy,
@interface PHJProxy : NSProxy
@property (nonatomic, weak) id target;
@end
@implementation PHJProxy //方法1: //// 发送给target //- (void)forwardInvocation:(NSInvocation *)invocation { // [invocation invokeWithTarget:self.target]; //} //// 给target注册一个方法签名 //- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel { // return [self.target methodSignatureForSelector:sel]; //} // 方法2: //仅仅添加了weak类型的属性还不够,为了保证中间件能够响应外部self的事件,需要通过消息转发机制,让实际的响应target还是外部self,这一步至关重要,主要涉及到runtime的消息机制。 -(id)forwardingTargetForSelector:(SEL)aSelector { return self.target; } @end
这2种方式原理都是一样,使用消息的转发机制,把消息转发到 target 中
@implementation NSTimer (LWTimer) + (NSTimer *)lw_timerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats { return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(timermethod:) userInfo:[block copy] repeats:YES]; } + (void)timermethod:(NSTimer *)timer { void (^block)() = timer.userInfo; if (block) { block(); } } @end
上述创建方式调用者是NSTImer自己,只是NSTimer捕获了参数block。这样我们在使用timer时,由于target的改变,就不再有循环引用了。
使用方式:
__weak typeof(self)weakself = self;
_timer = [NSTimer lw_timerWithTimeInterval:2 block:^{ weakself.count++; NSLog(@"-------%ld",weakself.count); } repeats:YES];
iOS10中,定时器的API新增了block方法,实现原理与此类似,这里采用分类为NSTimer添加了带有block参数的方法,而系统是在原始类中直接添加方法,最终的行为是一致的。
1、把timer改成弱引用
@property (nonatomic, weak) NSTimer *timer;
2. 使用__weak 那换个思路能不能让NSTimer弱引用target
__weak typeof(self) weakSelf = self; self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakSelf selector:@selector(showMsg) userInfo:nil repeats:YES];
原文:https://www.cnblogs.com/liuwenqiang/p/13214275.html