接上篇的讲解,项目实战定义了一个不需要手动释放的NSTimer
实现思路:了解定时器的同学肯定知道,定时器会保留其目标对象,目标对象又同时持有了定时器。只有在定时器失效时释放目标对象,但程序中反复执行定时任务容易出现内存泄露的问题。首先自定义了一个target,在target里定义了一个weak修饰的timer,target里还定义了timer所应执行任务的方法,并将此方法封装成块来调用的。然后写了一个NSTimer的分类,将target指向我们自定义的target,然后重写了部分定时器相关的方法
//NSTimer+AutoIncalidate.h
#import <Foundation/Foundation.h>
typedef void(^ZDTimeTargetBlock)(NSTimer *timer);
@interface ZDTimerTarget : NSObject
@end
@interface NSTimer (AutoIncalidate)
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti
block:(ZDTimeTargetBlock)block
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo
existObject:(id)existObj;
- (void)pauseTimer;
- (void)resumeTimer;
- (void)resumeTimerAfterTimeInterval:(NSTimeInterval)interval;
@end
#import "NSTimer+AutoIncalidate.h"
@interface ZDTimerTarget ()
@property (nonatomic ,weak)NSTimer *timer; //注意是weak
@property (nonatomic,copy) ZDTimeTargetBlock block;
@property (nonatomic,weak) id existObj; //注意是weak
@end
@implementation ZDTimerTarget
- (id)initWithTimerTargetBlock:(ZDTimeTargetBlock)block timer:(NSTimer *)timer existObj:(id)existObj {
if (self = [super init]) {
_block = block;
_timer = timer;
_existObj = existObj;
}
return self;
}
- (void)incocaiton {
if (_existObj) {
if ((_block)) {
_block(_timer);
}
}else {
[_timer invalidate];
_timer = nil;
}
}
@end
@implementation NSTimer (AutoIncalidate)
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)intervval
block:(ZDTimeTargetBlock)block
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo
existObject:(id)existObj
{
ZDTimerTarget *target = [[ZDTimerTarget alloc] initWithTimerTargetBlock:block timer:nil existObj:existObj];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:intervval target:target selector:@selector(incocaiton) userInfo:userInfo repeats:yesOrNo];
target.timer = timer;
return timer;
}
-(void)pauseTimer
{
if (![self isValid]) {
return ;
}
[self setFireDate:[NSDate distantFuture]];
}
-(void)resumeTimer
{
if (![self isValid]) {
return ;
}
[self setFireDate:[NSDate date]];
}
- (void)resumeTimerAfterTimeInterval:(NSTimeInterval)interval
{
if (![self isValid]) {
return ;
}
[self setFireDate:[NSDate dateWithTimeIntervalSinceNow:interval]];
}
@end