凡事有因必有果,正如问题的发现必定伴随问题的解决。再来说标题中的问题,相信一路过来的同胞都可能遇到,勤快一点的肯定也积累了解决问题的一二三,本人班门弄斧来码篇文章。
首先本片文章暂不涉及Dispatch Source Timer 的使用以及注意事项,单单来谈谈NSTimer的释放问题,至于为什么会出现NSTimer释放不掉,本文章不再细究(无非就是多重强引用的问题),一般遇到NSTimer释放问题主要的解决方向:
一、主动添加invalidate事件(按钮事件、手势事件、代理回调等事件)
- (void)invalidateAction:(id)sender {
[timer invalidate]; // timer 为定义的NSTimer变量
}
二、自定义类承载target
@interface CustomTimerTarget : NSObject
@property(nonatomic,weak)idtarget;
@property(nonatomic,assign) SEL selector;
@property(nonatomic,weak)NSTimer* timer;
@end
@implementation CustomTimerTarget
@end
三、使用block块来实现计时业务代码
+ (NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block userInfo:(id)userInfo repeats:(BOOL)repeats {
return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(timeBlockAction:) userInfo:@[[block copy], userInfo] repeats:repeats];
}
+ (void)timeBlockAction:(NSArray*)userInfo {
void (^block)() = userInfo[0];
id info = userInfo[1];
if(block) {
block(info);
}
}
然后就可以在block中编写美丽的代码了:
-(void)customTimerAction:(id)sender{
NSTimer *timer = [NSTimer TimerscheduledTimerWithTimeInterval:3.0f block:^(id userInfo) {
NSLog(@"%@", userInfo);
}userInfo:@"Fire"repeats:YES];
[timer fire];
}
到此问题解决,ViewController完美调用dealloc ,多年的“便秘”药到病除。
以上解决方法基本被大家熟知,所以再来加点新鲜的,直接上菜:
▶︎1.ios 10之后苹果提供了新的API
+ (NSTimer*)timerWithTimeInterval:(NSTimeInterval)intervalrepeats:(BOOL)repeatsblock:(void(^)(NSTimer*timer))blockAPI_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
/// - parameter: block The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references
说明文档中也提到了cyclical references,此API可以避免循环引用的问题;
Demo:
__weak typeof(self) weakSelf = self;
NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
weakSelf.testLab.text =@"***";
//demo
if (/** condition **/) {
[timer invalidate];
}
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
▶︎2.换个思维考虑,VC(ViewController)在被pop和dissmiss后,视图层的肯定会有所变化,所以沿着这条线又发现新大陆:
VC在pop和dismiss前,view也存在一个superView,也就是view的载体Wrapper视图
view存在一个包装层在VC被pop和dismiss后,view也从WrapperView中移除
view从包装层移除根据以上思路又可以愉快地敲那美丽的代码:
- (IBAction)startTimerAction:(id)sender {
NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(customTimerEvent:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)customTimerEvent:(NSTimer*)timer {
//demo
if (!self.view.superview) {
[timer invalidate];
return;
}
if (/** condition **/) {
[timer invalidate];
}
}
最后VC又完美的dealloc,到此本文章也告一段落。
上述内容,如有错误,欢迎指教(⁎⁍̴̛ᴗ⁍̴̛⁎)
网友评论