美文网首页iOS开发iosiOS
iOS中代理属性为什么要用Weak修饰?

iOS中代理属性为什么要用Weak修饰?

作者: forvert | 来源:发表于2016-02-18 15:33 被阅读4832次

    iOS中代理属性为什么要用Weak修饰?

    一.写在前面

    代理设计模式,在iOS开发过程中,是一个非常常见的设计模式,可以说用的范围非常广泛,而对初学者来讲,常常对代理的属性修饰用weak存在疑惑,因此下面就解释一下其中非常简单的道理.

    二.必要的知识补充.

    • 众所周知,OC是一门面向对象的语言,因此,对象这个词,在iOS中是个非常重要的词汇了(扯淡).开发中,创建一个对象是再常见不过的事儿了,每个对象的创建都需要在内存中分配一定的空间,简单的说,因为内存是有限的,所以一些没有必要存在的对象,我们需要及时的去将它释放,还原更多的内存空间(如果不进行释放就会造成"内存泄露").
    • 因此,在iOS中引入了引用计数(retainCount)这个词汇,规定:只要引用计数为零,对象就会被释放,注意是规定,规定就不要问为什么了.
    • 这里主要介绍strong和weak两个修饰词(不能偏离重点),如果想了解其他的修饰词(retain,copy,getter,setter...),可以Google一下,简单点来讲strong属性会使引用计数+1,而weak修饰的对象不会使引用计数改变.
    • OK了,有了上面的只是准备,应该可以理解下面的要解释的东西了.

    三.案例说明

    1. 案例介绍
    ```
        案例中的类介绍: 案例共用到三个类,Baby类(婴儿类),LLBabyServant类(保姆类),ViewControllr类(控制器类),其中说明问题的关键是之前两个类.
        假设,婴儿类要想做一些事情(像换衣服了,方便了之类的...)就必须具有代理的属性,因此指定了一个协议<LLBabyDelegate>,合情合理.而保姆需要成为婴儿的代理,必须遵循协议,废话不多说,上代码!
    ```
    
    1. 首先介绍Baby类-----.h文件
    ```
    // 制定协议
    @protocol LLBabyDelegate <NSObject>
    //这里可以编写代理方法(该案例中用不到所以就不写了)
    @end
    
    @interface Baby : NSObject
    /**
     *  baby的代理属性(这里用的是weak修饰,正确的做法)
     */
    @property(nonatomic, weak) id<LLBabyDelegate>delegate;
    @end
    
    ```
    
    说明:跟上面描述的一样婴儿拥有一个代理的属性.并且用修饰词Weak修饰的.
    
    接着粘Baby类-----.m文件
    
    ```
    @implementation Baby
    - (void)dealloc
    {
        NSLog(@"Baby被销毁了");
    }
    @end
    ```
    说明:该方法的作用是当该类的对象被销毁时会调用-dealloc方法(在这个案例中用来观察对象是否被销毁了)
    
    1. 再有介绍BabyServant类-----.m文件

      //BabyServant类也就是保姆必须遵循代理协议 
      @interface BabyServant()<LLBabyDelegate>
      //并有一个需要照顾的Baby
      @property(nonatomic, strong) Baby *baby;
      
      @end
      
      @implementation LLBabyServant
      //初始化方法
      - (instancetype)init
      {
       self = [super init];
      
          if (self) {
          // 初始化'婴儿'对象
          self.baby = [[Baby alloc]init];
          // 设置'自己(LLBabyServant)'为(Baby)类的代理
          self.baby.delegate = self;
          }
      
       return self;
      }
      
    2. 我们介绍最后一个类 ViewController类

      @implementation ViewController
      
      - (void)viewDidLoad {
          [super viewDidLoad];
      
          LLBabyServant *servant = [[LLBabyServant alloc]init];
      
          }
      
      @end
      
      

      说明: 在ViewController的方法ViewDidLoad中创建保姆对象,并且该对象作用的范围是这个方法内部.这个方法执行完成,servant对象就会被销毁了.

      上面的代码执行完成之后,运行结果如下:

        2016-02-18 15:06:41.151 代理weak案例[1805:173874] LLBabyServant 被销毁了
        2016-02-18 15:06:41.152 代理weak案例[1805:173874] Baby类被销毁了
        
        
    这就说明LLBabyServant对象和Baby对象在没有用处之后都会被销毁,但是如果用代理用strong修饰,而不是用weak修饰,则不会打印上面的结果!
    

    四.分析

    1. 用weak分析图如下:
    • 整体来看如下图

    • 分开来看如下图:

      如果weak的话,在程序运行的时候不会造成循环引用,对象都会被顺利的销毁,所以会调用婴儿类和保姆类的delloc方法

    2. 用strong分析如下
    • 整体来看如下图

    • 分开来看如下图


      如果strong的话,在程序运行的时候会造成循环引用(意思就是reatainCount不为0,只要有实线引用,计数器就+1),对象都不会的销毁,所以会调用婴儿类和保姆类不会调用delloc方法,从而造成了内存泄露的问题

    这就是为什么代理属性要用weak修饰的原因了!如果有哪里不严谨或者错误的地方,希望能够多多交流.

    相关文章

      网友评论

      • gkk888:一个循环引用,只需要 A B 两个类举例即可,你为什么会引入三个类呢,绕来绕去的
      • 会飞的盖伦:并不是所有的代理都必须用weak,有时候可以用strong来保证代理不被释放
      • 超_iOS:能分析下weak和assin 的区别吗
        封丑儿:@马面 assign修饰对象,对象被销毁后,对象指针并没有被销毁,会出现野指针
        马面:@_超 weak和assign都不会增加引用计数,区别是修饰的对象在释放时所做的操作不同,weak是会把对象置为nil,assign则不会,assign一般适用与基本数据类型

      本文标题:iOS中代理属性为什么要用Weak修饰?

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