timerWithTimeInterval
创建出来的timer无法立刻使用,需要添加到NSRunloop中才可以正常工作, 相当于runloop强持有timer, timer又强持有self, 导致无法释放
一: 手动销毁定时器
但存在一些弊端, 比如push到下个页面时,当前页面仍在内存中,定时器仍在计时,来回关闭开启很麻烦
在viewWillDisappear
[self.timer invalidate];
self.timer = nil;
或pop时在didMoveToParentViewController中
if (nil == parent) { [self.timer invalidate]; self.timer = nil; }
二: 自定义定时器, 添加target和selector, timer对self弱引用
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface TimerWrapper : NSObject - (id) initWithTimerInterval:(NSTimeInterval)interval target:(id)target selector:(SEL) sel; - (void) stop; @end #import "TimerWrapper.h" @interface TimerWrapper() @property (nonatomic, weak) id target; @property (nonatomic, assign) SEL sel; @property (nonatomic, strong) NSTimer* timer; @end @implementation TimerWrapper - (id) initWithTimerInterval:(NSTimeInterval)interval target:(id)target selector:(SEL) sel { if (self = [super init]) { self.target = target; self.sel = sel; self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES]; } return self; } - (void) fire { if ([self.target respondsToSelector:self.sel]) { [self.target performSelector:self.sel]; } } - (void) stop { [self.timer invalidate]; self.timer = nil; } #import "TZViewController.h" #import "TimerWrapper.h" @interface TZViewController () //@property (nonatomic, strong) NSTimer* timer; @property (nonatomic, strong) TimerWrapper* timer; @end @implementation TZViewController - (void)viewDidLoad { [super viewDidLoad]; /// RunLoop -> timer -> target --> self self.timer = [[TimerWrapper alloc] initWithTimerInterval:1.0 target:self selector:@selector(fire)]; // self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES]; } //- (void) didMoveToParentViewController:(UIViewController *)parent { // if (nil == parent) { // [self.timer invalidate]; // self.timer = nil; // } //} - (void) fire { NSLog(@"%s", __func__); } - (void)dealloc { [self.timer stop]; NSLog(@"%s", __func__); }
三: 使用NSProxy, 借助一个虚基类NSProxy,(NSProxy其主要用来消息转发的处理, 自定义或者YYWeakProxy
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface WeakProxy : NSProxy @property (nonatomic, weak) id target; @end NS_ASSUME_NONNULL_END #import "WeakProxy.h" @implementation WeakProxy //获取当前的方法签名 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { return [self.target methodSignatureForSelector:sel]; } //指定当前消息的处理者 - (void) forwardInvocation:(NSInvocation *)invocation { [invocation invokeWithTarget:self.target]; } @end #import "TZViewController.h" #import "WeakProxy.h" @interface TZViewController () //@property (nonatomic, strong) id target; @property (nonatomic, strong) NSTimer* timer; @property (nonatomic, strong) WeakProxy* proxy; @end @implementation TZViewController - (void)viewDidLoad { [super viewDidLoad]; //虚基类只有alloc方法,所以初始化,直接调用alloc self.proxy = [WeakProxy alloc]; //当前Proxy的target设为当前的self,因为真正要处理消息的其实是当前的viewcontroller(其实这个target就相当于delegate) self.proxy.target = self; self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self.proxy selector:@selector(fire) userInfo:nil repeats:YES]; } - (void) fire { NSLog(@"%s", __func__); } - (void)dealloc { [self.timer invalidate]; self.timer = nil; NSLog(@"%s", __func__); } @end
四: 引入中间者, 利用runtime, 动态添加方法, 将强引用转移到target上
#import "TZViewController.h" #import <objc/runtime.h> @interface TZViewController () @property (nonatomic, strong) id target; @property (nonatomic, strong) NSTimer* timer; @end @implementation TZViewController - (void)viewDidLoad { [super viewDidLoad]; /// RunLoop -> timer -> target ---> self self.target = [NSObject new]; class_addMethod([self.target class], @selector(fire), class_getMethodImplementation([self class], @selector(fire)), "v@:"); self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self.proxy selector:@selector(fire) userInfo:nil repeats:YES]; } - (void) fire { NSLog(@"%s", __func__); } - (void)dealloc { [self.timer invalidate]; self.timer = nil; NSLog(@"%s", __func__); } @end
五: 系统高于10.0时, 使用带block的timer, 兼容10.0以下可给NSTimer分类添加方法
__weak typeof(self) weakSelf = self; _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f repeats:YES block:^(NSTimer * _Nonnull timer) { __strong typeof(self) strongSelf = weakSelf; [strongSelf fire]; }];
首先我们创建一个NSTimer的分类, // NSTimer+ZHTimer.h #import <Foundation/Foundation.h> @interface NSTimer (ZHTimer) +(NSTimer *)zh_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(void))block; @end // NSTimer+ZHTimer.m #import "NSTimer+ZHTimer.h" @implementation NSTimer (ZHTimer) +(NSTimer *)zh_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(void))block { return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(zh_blockHandle:) userInfo:block repeats:YES]; //这里面这个self,其实指的是当前的类对象,在内存中只存在一份,就是以单例的形式存在,所以我们在每一次创建实例变量都要通过这个类对象来创建, //所以并不需要担心当前的target造成循环引用,因为单例不需要被释放,只有当APP被Q的时候,存在内存中的单例才会被释放掉。 } +(void)zh_blockHandle:(NSTimer *)timer{ void(^block)(void) = timer.userInfo; if (block) { block(); } } @end //调用 __weak typeof(self) weakSelf = self; _timer = [NSTimer zh_scheduledTimerWithTimeInterval:1.0f repeats:YES block:^{ __strong typeof(self) strongSelf = weakSelf; [strongSelf fire]; }];