NSTimer与循环引用

代码:

#import "ViewController.h"

@interface ViewController ()

@property (strong, nonatomic) NSTimer *timer;

- (void)doSomething:(NSTimer *)timer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 编程提示
    // A timer maintains a strong reference to its target.
    // This means that as long as a timer remains valid, its target will not be deallocated.
    // As a corollary, this means that it does not make sense for a timer’s target to try to invalidate the timer in its dealloc method,
    // the dealloc method will not be invoked as long as the timer is valid.

    // target参数
    // The object to which to send the message specified by aSelector when the timer fires.
    // The timer maintains a strong reference to this object until it (the timer) is invalidated.
    NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(doSomething:) userInfo:nil repeats:YES];

    // The receiver retains aTimer.
    // To remove a timer from all run loop modes on which it is installed, send an invalidate message to the timer.
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

    self.timer = timer;
}

- (void)doSomething:(NSTimer *)timer {
    NSLog(@"%s", __func__);
}

- (void)dealloc {
    NSLog(@"%s", __func__);
    [self.timer invalidate];
}

@end

上述代码中,由于timer会在其有效期内保持对其target的强引用,而target自身也就是当前的viewController又通过一个使用strong修饰符修饰的属性对timer产生强引用,最终产生循环引用。

并且在本例中,由于runLoop会引用被添加至其中的timer,从而产生了一个永远无法被自行打破的循环引用。

由于循环引用的存在,即便当前viewController从导航控制器的导航栈中弹出,其dealloc方法也不会被调用。所以在dealloc方法中,调用timer的invalidate方法是没有意义的。

一种可行的办法是重写viewController的viewWillDisappear:或viewDidDisappear:方法,在其方法体内调用timer的invalidate方法,从而解除timer对target即viewController的强引用,最终打破循环引用。

代码-修改版:

#import "ViewController.h"

@interface ViewController ()

@property (strong, nonatomic) NSTimer *timer;

- (void)doSomething:(NSTimer *)timer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(doSomething:) userInfo:nil repeats:YES];

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

    self.timer = timer;
}

- (void)doSomething:(NSTimer *)timer {
    NSLog(@"%s", __func__);
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    NSLog(@"%s", __func__);
    [self.timer invalidate];
}

- (void)dealloc {
    NSLog(@"%s", __func__);
}

@end
时间: 2024-11-05 17:10:02

NSTimer与循环引用的相关文章

iOS 里面 NSTimer 防止 循环引用

使用NSTimer的类 #import "TBTimerTestObject.h" #import "TBWeakTimerTarget.h" @interface TBTimerTestObject() @property (nonatomic, weak) NSTimer *timer; @end @implementation TBTimerTestObject - (void)dealloc { NSLog(@"timer is dealloc&q

NSTimer解除循环引用

NSTimer作为一个经常使用的类,却有一个最大的弊病,就是会强引用target.造成调用timer很麻烦.稍有不慎就造成内存泄漏. 下面就是为解决问题做的封装. 直接上代码: #import <Foundation/Foundation.h> @interface LZLTimer : NSObject -(void)startTimerInterval:(NSTimeInterval)ti target:aTarget selector:(SEL)selector userInfo:(id

iOS容易造成循环引用的三种场景NSTimer以及对应的使用方法(一)

NSTimer A timer provides a way to perform a delayed action or a periodic action. The timer waits until a certain time interval has elapsed and then fires, sending a specified message to a specified object(timer就是一个能在从现在开始的未来的某一个时刻又或者周期性的执行我们指定的方法的对象)

初识iOS NSTimer 循环引用不释放问题

原文转自 :http://www.codecate.com/code/?p=77 最近开发遇到NSTimer Target 造成循环引用问题,不释放,以下是解决方案. stackoverflow上的一个解决方案 http://stackoverflow.com/questions/16821736/weak-reference-to-nstimer-target-to-prevent-retain-cycle 原文如下 Weak Reference to NSTimer Target To Pr

用block解决nstimer循环引用

大多数开发者可能都会这样来实现定时器.创建定时器的时候,由于目标对象是self,所以要保留此实例.然而,因为定时器是用实例变量存放的,所以实例也保留了定时器,这就造成了循环引用.除非调用stop方法,或者系统回收实例,才能打破循环引用,如果无法确保stop一定被调用,就极易造成内存泄露.当指向XXClass实例的最后一个外部引用移走之后,该实例仍然会继续存活,因为定时器还保留着它.而定时器对象也不可能被系统释放,因为实例中还有一个强引用正在指向它.这种内存泄露是很严重的,如果定时器每次轮训都执行

解决NSTimer或CADisplayLink计时器造成的循环引用问题。

众所周知,我们在使用NSTimer或者CADisplayLink的时候,经常会导致引用它们的类不能正常释放,那是因为引用它们的类与它们之间产生了循环引用.看以下代码: self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(runTimer) userInfo:nil repeats:YES]; self.displayLink = [CADisplayLink display

【IOS学习基础】weak和strong、懒加载、循环引用

一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成引用计数加1:而strong则相当于OC中规定retain,它会造成引用计数加1”. ARC的原理:只要还有一个变量指向对象,对象就会保持在内存中.当指针指向新值,或者指针不再存在时,相关联的对象就会自动释放.这条规则对于实例变量.synthesize属性.局部变量都是适用的 strong指针能够保

ios循环引用

一.parent-child相互持有.委托模式[案例]:@interface FTAppCenterMainViewController (){}@property(weak,nonatomic) UITableView* myTableView;@end这里面的myTableView就使用了weak修饰符.@property (nonatomic, weak)  iddelegate;[推荐方法]:child只有parent的对象为weak类型:@property (nonatomic, we

block的学习(block和timer的循环引用问题)

一.什么是回调函数? 回调函数,本质上也是个函数(搁置函数和方法的争议,就当这二者是一回事).由"声明"."实现"."调用"三部分组成. 在上面的例子中,我可以看出,函数amount(其实是Block),的声明和调用在A类中,而实现部分在B类中.也就是说,B类实现了amount函数,但并没有权限调用,最终还是 由A类触发调用.我们称这样的机制为"回调".意思是"虽然函数的实现写在B类中,但是真正的调用还是得由A类来完