• 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
  • 相关阅读:
    分享:liblfds 6.1.0 发布,C 数据结构库
    strchr C++ Reference
    爱上MVC3系列~PartialView中的页面重定向
    基础才是重中之重~Conditional特性使代码根据条件在debug或者release模式中执行
    爱上MVC3系列~Html.BeginForm与Ajax.BeginForm
    爱上MVC3系列~Razor页面中的共享namespace不起作用了(解决自定义扩展方法不能识别的问题)
    爱上MVC3系列~RenderAction与RenderPartial及一个页面多个表单提交
    NHibernate Criteria中的And, Or
    poj 2528 Mayor's posters(线段树区点)
    探索iptables BPF模块的悲惨历程
  • 原文地址:https://www.cnblogs.com/xwoder/p/4780121.html
Copyright © 2020-2023  润新知