美文网首页
ios中循环引用问题

ios中循环引用问题

作者: 简而为之 | 来源:发表于2017-04-11 15:45 被阅读0次

    ios中循环引用问题

    ARC自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露。导致iOS对象无法按预期释放的一个无形杀手是——循环引用。循环引用主要有以下3个情形出现:
    

    NO1: NSTimer
    问题:当你创建使用NSTimer的时候,NSTimer会默认对当前self有个强引用,所有在self使用完成打算是否的时候,一定要先使用NSTimer的invalidate来停止是否时间控制对self的引用

    #import <Foundation/Foundation.h>
    @interface Student : NSObject
    - (void)cleanTimer;
    @end
    
    #import "Student.h"
    @interface Student () {
        NSTimer *_timer;
    }
    @end
    @implementation Student
    - (id)init{
      if (self = [super init]) {
            _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleTimer:) userInfo:nil repeats:YES];
        }
       return  self;
    }
    - (void)handleTimer:(id)sender{
       NSLog(@"%@ say: Hi!", [self class]);
    }
    - (void)cleanTimer {
      [_timer invalidate];
       _timer = nil;
    }
    //time角度,当student被释放时  销毁timer
    //student角度 当timer停止时销毁 这样两者形成相互不销毁 循环引用,互相等待
    - (void)dealloc{
        [self cleanTimer];
        NSLog(@"[Student class] is dealloced");
    }
    @end
    
    #import "ViewController.h"
    #import "Student.h"
    @interface ViewController ()
    @en
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        Student *stu = [[Student alloc] init];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5*NSEC_PER_SEC), dispatch_get_main_queue(), ^{
             //释放stu [stu release]; 错误方式:执行到此会判断stu对象是否还有持有的对象,若还有则不被释放 (NStimer)
             [stu cleanTimer]; //确定不用的时候主动销毁 正确方式
           });
    }
    

    NO2:Block
    Block也是比较常见的循环引用问题,在Block中使用了self容易出现循环引用,因此很多人在使用block的时候,加入里面有用到self的操作都会声明一个__weak来修饰self。其实便不是这样的,不是所有使用了Block都会出现Self循环引用问题,只有self拥有Block的强引用才会出现这种情况。Block在copy时都会对Block内部用到的对象进行强引用(ARC)或者retainCount增1(非ARC)。在ARC与非ARC环境下对block使用不当都会引起循环引用问题,一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身.

      self.arr = @[@111, @222, @333];
            self.block = ^(NSString *name){
                NSLog(@"arr:%@", self.arr);//不一定要显式地出现"self"字眼才会引起循环引用
            };
    //修改一下代码
    self.arr = @[@111, @222, @333];
            self.block = ^(NSString *name){
                NSLog(@"_arr:%@", _arr);//不通过属性self.arr去访问arr变量,而是通过实例变量_arr去访问 一样会提示 循环引用问题
            };
    

    通过如下方法解决:

        __weak __typeof__(self) weakSelf = self;    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            
            [weakSelf doSomething];//
            [weakSelf doOtherThing]; //在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放,于是,strongSelf 就派上用场了:
            /*__strong __typeof(self) strongSelf = weakSelf;*/
        });
    

    总结
    1 在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。
    2 如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。

    NO3:delegate
    Delegate是ios中开发中最常遇到的循环引用,一般在声明delegate的时候都要使用弱引用weak或者assign

    @property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
    

    当然怎么选择使用assign还是weak,MRC的话只能用assign,在ARC的情况下最好使用weak,因为weak修饰的变量在是否后自动为指向nil,防止不安全的野指针存在.

    相关文章

      网友评论

          本文标题:ios中循环引用问题

          本文链接:https://www.haomeiwen.com/subject/smhuattx.html