NSTimer 就是我们的定时器 可以满足我们很多业务需求 ,但是它会带来内存泄漏的隐患.
场景:在一个VC中设定一个全局定时器定时打印log,需要在pop该VC的时候 清除定时器 减少内存泄露
解决如下:
001 生命周期 处理
- (void)didMoveToParentViewController:(UIViewController *)parent{
NSLog(@"didMoveToParent==%@",parent);
//parent 就是当前的视图控制器的UINavigationController
if (parent == nil) {
[self.timer invalidate];
self.timer = nil;
}
}
002 设置消息转发
@property (nonatomic,strong) id target;
class_addMethod([_target class], @selector(fire), (IMP)fireImp,"V@:");
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:_target selector:@selector(fire) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
void fireImp(id self,SEL _cmd){
NSLog(@"fire.......fireImp");
}
- (void)dealloc{
NSLog(@"VV dealloc");
[self.timer invalidate];
self.timer = nil;
}
003 中转代理
@interface RunTimeProxy : NSProxy
@property (nonatomic, weak) id target;
@end
#import "RunTimeProxy.h"
@implementation RunTimeProxy
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation{
[invocation invokeWithTarget:self.target];
}
@end
在VC中引入代理
@property (nonatomic,strong) RunTimeProxy *proxy;
_proxy = [RunTimeProxy alloc];
_proxy.target = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:_proxy selector:@selector(fire) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
- (void)fire{
NSLog(@"fire.......");
}
- (void)dealloc{
NSLog(@"VV dealloc");
[self.timer invalidate];
self.timer = nil;
}
原则是让timer 不直接持有self 通过一些self的马甲套路: NSObject对象消息转发以及中转代理代理weak引用self,这样可以在pop执行之后就可以执行析构函数dealloc函数清除timer 移除在runLoop中.
来源:CSDN
作者:Coding_Physical
链接:https://blog.csdn.net/Coding_Physical/article/details/104113512