[crash详解与防护] NSTimer crash

前言:

  NSTimer会保留其目标对象,如果不加以注意,就会持有保留环,造成内存泄露。

一、 NSTimer保留环介绍

  Foundation框架中的NSTimer类,提供了在某个时间执行指定方法的功能,原型如下:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

  target和selector参数表示计时器将在哪个对象上调用哪个方法。repeats参数可以指定计时器是一次性的计时器还是重复模式的计时器。一次性的计时器在执行完相关任务之后就会失效。重复模式的计时器,必须手动调用invalidate方法,才能令其停止。

  重复执行的计时器很容易产生保留环而不能释放,如下所示:

//  SLVTimerTestViewController.m
@implementation SLVTimerTestViewController {
    NSTimer *_aTimer;
}

- (void)viewDidLoad {
    [super viewDidLoad];
     _aTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(timer_invoke) userInfo:nil repeats:YES];
}
-(void)dealloc {
    [_aTimer invalidate];
    NSLog(@"the timer vc dealloced!");
}

-(void)timer_invoke {
    NSLog(@"timer invoke!");
}

我们发现,当SLVTimerTestViewController不再展示的时候,并不会调用dealloc的方法,也就是SLVTimerTestViewController一直都不会释放。

原因是,NSTimer在使用scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:方法时会保留其目标对象self。而_aTimer又是self的变量,self也保留了_aTimer,这样就形成了保留环。而Timer没有主动置为失效的情况下,Timer一直会保留self,所以即使SLVTimerTestViewController已经没有其它对象使用了,也还是有Timer在持有他,一直不会释放,也一直不会调用dealloc。

二、NSTimer打破保留环的解决方案

  如下代码所示,可以使用block来打破保留环:可以定义一个弱引用,令其指向self,然后使块捕获这个引用,而不直接去捕获普通的self变量。也就是说,self不会为计时器所保留。当块开始执行时,立刻生成strong引用,以保证实例在执行期间持续存活。

//  SLVTimerTestViewController.m
@implementation SLVTimerTestViewController {
    NSTimer *_aTimer;
}

- (void)viewDidLoad {
    [super viewDidLoad];
     __weak SLVTimerTestViewController *weakSelf = self;
        _aTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 repeats:YES block:^(NSTimer* timer){
              SLVTimerTestViewController *strongSelf = weakSelf;
              [strongSelf timer_invoke];
        }];
}
-(void)dealloc {
    [_aTimer invalidate];
    NSLog(@"the timer vc dealloced!");
}

-(void)timer_invoke {
    NSLog(@"timer invoke!");
}

这样,我们就发现当没有其它对象使用SLVTimerTestViewController时,dealloc方法就会如期执行。这是在ios10之后苹果添加的新的方法,这个block的实现。在ios10之前自己可以用分类的方法实现如下:

//  NSTimer+SLVBlocksSupport.m
@implementation NSTimer (SLVBlocksSupport)
+(NSTimer *)slv_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                         block:(void(^)())block
                                       repeats:(BOOL)repeats {
    return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(slv_blockInvoke:) userInfo:[block copy] repeats:repeats];
}

-(void)slv_blockInvoke:(NSTimer *)timer {
    void (^block)() = timer.userInfo;
    if(block){
        block();
    }
}
@end
时间: 2024-12-28 06:24:04

[crash详解与防护] NSTimer crash的相关文章

[crash详解与防护] KVO crash

一.KVO介绍 KVO(Key-Value Observing),键值监听.它提供一种机制:指定的被观察者的属性被改变后,KVO就会通知观察者,观察者可以做出响应. KVO作用:利用KVO,很容易实现视图组件和数据模型的分离.当数据模型的属性值改变之后,作为监听者的视图组件就会被激发.这有利于业务逻辑和视图展示的解耦合. KVO使用步骤:(1)注册观察,添加观察者及属性:(2)实现回调方法:(3)移除观察. (1)注册观察: - (void)addObserver:(NSObject *)obs

CSRF(跨站请求伪造攻击)详解以及防护之道

CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,该攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在并未授权的情况下执行在权限保护之下的操作,有很大的危害性.然而,该攻击方式并不为大家所熟知,很多网站都有 CSRF 的安全漏洞.本文首先介绍 CSRF 的基本原理与其危害性,然后就目前常用的几种防御方法进行分析,比较其优劣.最后,本文将以实例展示如何在网站中防御 CSRF 的攻击,并分享一些开发过程中的最佳实践. C

iOS 中 NSTimer 使用详解-北京尚学堂

iOS 中 NSTimer 使用详解-北京尚学堂 前阵子在整理公司项目的时候,发现老代码在使用 NSTimer 时出现了内存泄露.然后整理了一些 NSTimer 的相关内容.比较简单,各位见笑啦. NSTimer fire 我们先用 NSTimer来做个简单的计时器,每隔5秒钟在控制台输出 Fire .比较想当然的做法是这样的: @interface DetailViewController () @property (nonatomic, weak) NSTimer *timer; @end

[gitbook] Android框架分析系列之Android Binder详解

请支持作者原创: https://mr-cao.gitbooks.io/android/content/android-binder.html Android Binder详解 Table of Contents 1. binder简介 2. binder的实现 2.1. IBinder类简介 2.2. IInterface类简介 2.3. BpBinder和BBinder简介 2.4. ProcessState和IPCThreadState简介 2.5. ServiceManager简介 2.

Android严苛模式StrictMode使用详解

StrictMode类是Android 2.3 (API 9)引入的一个工具类,可以用来帮助开发者发现代码中的一些不规范的问题,以达到提升应用响应能力的目的.举个例子来说,如果开发者在UI线程中进行了网络操作或者文件系统的操作,而这些缓慢的操作会严重影响应用的响应能力,甚至出现ANR对话框.为了在开发中发现这些容易忽略的问题,我们使用StrictMode,系统检测出主线程违例的情况并做出相应的反应,最终帮助开发者优化和改善代码逻辑. 官网文档:http://developer.android.c

JSPatch实现原理详解<二>

本文转载至 http://blog.cnbang.net/tech/2855/ 距离上次写的<JSPatch实现原理详解>有一个月的时间,在这段时间里 JSPatch 在不断地完善和改进,代码已经有很多变化,有一些修改值得写一下,作为上一篇的补充. Special Struct 先说下 _objc_msgForward,在上一篇提到为了让替换的方法走 forwardInvocation,把它指向一个不存在的 IMP: class_getMethodImplementation(cls, @se

iOS开发——高级特性&amp;Runtime运行时特性详解

Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 简介 与Runtime交互 Runtime术语 消息 动态方法解析 消息转发 健壮的实例变量(Non Fragile ivars) Objective-C Associated Objects Method Swizzling 总结 引言 曾经觉得Objc特别方便上手,面对着 Cocoa 中大量

Android 4.4 KitKat NotificationManagerService使用详解与原理分析(一)__使用详解

概况 Android在4.3的版本中(即API 18)加入了NotificationListenerService,根据SDK的描述(AndroidDeveloper)可以知道,当系统收到新的通知或者通知被删除时,会触发NotificationListenerService的回调方法.同时在Android 4.4 中新增了Notification.extras 字段,也就是说可以使用NotificationListenerService获取系统通知具体信息,这在以前是需要用反射来实现的. 转载请

红帽Linux故障定位技术详解与实例(2)

红帽Linux故障定位技术详解与实例(2) 2011-09-28 14:26 圈儿 BEAREYES.COM 我要评论(0) 字号:T | T 在线故障定位就是在故障发生时, 故障所处的操作系统环境仍然可以访问,故障处理人员可通过console, ssh等方式登录到操作系统上,在shell上执行各种操作命令或测试程序的方式对故障环境进行观察,分析,测试,以定位出故障发生的原因. AD:2014WOT全球软件技术峰会北京站 课程视频发布 3.内核故障情形及处理 (1)内核panic panic是内