demo下载地址
_timer = [NSTimer scheduledTimerWithTimeInterval:3.0f
target:self
selector:@selector(timerFire:)
userInfo:nil
repeats:YES];
[_timer fire];
-(void)dealloc {
[_timer invalidate];
NSLog(@"%@ dealloc", NSStringFromClass([self class]));
}
参考博客1 参考博客2
在使用NSTimer时发现,当页面返回时计时器并没有停止
也就是说,VC的销毁方法并没有走,VC并没有被销毁,查询得知
timer是在Runloop中运行的,会被Runloop强引用
Note
in
particular that run loops maintain strong references to their timers, so you don’t have to maintain your own strong reference to a timer after you have added it to a run loop.
而Timer的Target的也会强引用VC,导致VC不能被释放,所以dealloc不会被调用,Timer也不会被销毁。
第一种方法,暴力的解决办法,
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.timer invalidate];
self.timer = nil;
}
可以解决部分情景下的Timer和VC的释放问题,但是如果VC界面消失时并不想销毁Timer那怎么办呢,基本思路就是提供一个"假"target给timer,
第二种方法,创建一个中间类,让中间类弱引用VC,当VC执行dealloc方法时,在dealloc里销毁timer。
参考博客
第三种方法,创建timer的分类,将timer的target指向分类的静态方法,分类的实现方法如下,demo地址
+ (NSTimer *)helper_scheduedTimerWithTimeInterval:(NSTimeInterval)seconds
block:(void(^)(id info))block
userinfo:(id)userinfo
repeats:(BOOL)repeats;
//将nstimer的target指向NSTimer类和类方法
+ (NSTimer *)helper_scheduedTimerWithTimeInterval:(NSTimeInterval)seconds
block:(void (^)(id))block
userinfo:(id)userinfo
repeats:(BOOL)repeats
{
return [NSTimer scheduledTimerWithTimeInterval:seconds
target:self
selector:@selector(helper_block:)
userInfo:@[[block copy] , userinfo]
repeats:repeats];
}
//在类方法中回调block
+ (void)helper_block:(NSTimer *)timer
{
NSArray *infoArr = timer.userInfo;
void (^myblock)(id userinfo) = infoArr[0];
id info = infoArr[1];
if (myblock) {
myblock(info);
}
}
使用时的代码如下
@weakify(self);
self.timer = [NSTimer helper_scheduedTimerWithTimeInterval:1.0 block:^(id info) {
@strongify(self);
[self print:info];
} userinfo:@[@"1" , @"2"] repeats:YES];
- (void)print:(id)info
{
NSLog(@"执行block:%@" , info);
}
- (void)dealloc
{
[self.timer invalidate];
self.timer = nil;
NSLog(@"销毁了B");
}
第四种办法,使用苹果最新的方法
+ (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));
这个方法跟第三种方法比较类似,苹果在这个方法中解决了内存泄露的问题,但是这个方法的版本比较高,使用不方便。
标注:weakly和strongify是yykit里的一个宏定义,
/**
Synthsize a weak or strong reference.
Example:
@weakify(self)
[self doSomething^{
@strongify(self)
if (!self) return;
...
}];
*/
#ifndef weakify
#if DEBUG
#if __has_feature(objc_arc)
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
#endif
#else
#if __has_feature(objc_arc)
#define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
#endif
#endif
#endif
#ifndef strongify
#if DEBUG
#if __has_feature(objc_arc)
#define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
#endif
#else
#if __has_feature(objc_arc)
#define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
#endif
#endif
#endif