为什么代理要用weak?

作者: heweiming 分类: iOS基础 发布时间: 2017-04-25 21:08

一.写在前面

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

二.必要的知识补充.

众所周知,OC是一门面向对象的语言,因此,对象这个词,在iOS中是个非常重要的词汇了(扯淡).开发中,创建一个对象是再常见不过的事儿了,每个对象的创建都需要在内存中分配一定的空间,简单的说,因为内存是有限的,所以一些没有必要存在的对象,我们需要及时的去将它释放,还原更多的内存空间(如果不进行释放就会造成"内存泄露").

因此,在iOS中引入了引用计数(retainCount)这个词汇,规定:只要引用计数为零,对象就会被释放,注意是规定,规定就不要问为什么了.
这里主要介绍strong和weak两个修饰词(不能偏离重点),如果想了解其他的修饰词(retain,copy,getter,setter...),可以Google一下,简单点来讲strong属性会使引用计数+1,而weak修饰的对象不会使引用计数改变.

在开发中我们经常使用代理,或自己写个代理,而代理属性都用weak(assign)修饰,看过有些开发者用strong(retain),但并没发现有何不妥,也不清楚weak(assign)与strong(retain)修饰有何区别

  • weak:指明该对象并不负责保持delegate这个对象,delegate这个对象的销毁由外部控制
  • @property (nonatomic, weak) id<HWDogDelegate>delegate;
    
  • strong:该对象强引用delegate,外界不能销毁delegate对象,会导致循环引用(Retain Cycles)
  • @property (nonatomic, strong)id<HWDogDelegate>delegate;
    

    三、来个栗子

  • HWDog类
  • //HSDog.h
    
    @protocol HWDogDelegate <NSObject>
    @end
    
    @interface HWDog : NSObject
    
    @property (nonatomic, weak) id<HWDogDelegate>delegate;
    
    @end
    
    //HWPerson.m
    
    #import "HWDog.h"
    
    @implementation HWDog
    
    - (void)dealloc
    {
        NSLog(@"HWDog----销毁");
    }
    
    @end
    
  • HWPerson类
  • //HWPerson.h
    
    @interface HWPerson : NSObject
    
    @end
    
    //HWPerson.m
    
    #import "HWPerson.h"
    #import "HWDog.h"
    
    @interface HWPerson()<HWDogDelegate>
    /** 强引用dog*/
    @property (nonatomic, strong) HWDog *dog;
    @end
    
    @implementation HWPerson
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            // 实例化dog
            self.dog = [[HWDog alloc] init];
            // dog的delegate引用self,self的retainCount,取决于delegate修饰,weak:retainCount不变,strong:retainCount + 1
            self.dog.delegate = self;
    
        }
        return self;
    }
    
    - (void)dealloc
    {
        NSLog(@"HWPerson----销毁");
    }
    
    @end
    
    //在ViewController实现
    #import "ViewController.h"
    #import "HWPerson.h"
    
    @interface ViewController ()
    @end
    
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 实例化person, self对person弱引用,person的retainCount不变
        HWPerson *person = [[HWPerson alloc] init];
    
    }
    @end
    

    结果:

  • weak修饰代理
  • @property (nonatomic, weak) id<HWDogDelegate>delegate;
    
  • 运行->打印:
  • HWPerson----销毁
    HWDog----销毁
    
  • strong修饰代理
  • @property (nonatomic, strong)id<HWDogDelegate>delegate;
    
  • 运行->打印:
  • ....并未打印,说明HWPerson、HWDog对象没调用dealloc方法,两个对象未销毁
    这也是我们经常说的内存泄露,该释放的内存并未释放!
    

    分析:

  • 使用strong
  • delegate-strong
    //person对dog强引用
    
    @property (nonatomic, strong) HWDog *dog; person
    
    
    //self.dog.delegate又对person强引用,使person的retainCount + 1
    
    @property (nonatomic, strong)id<HWDogDelegate>delegate;
    

    当viewController不对person引用后,dog.delegate对person还强引用着,person的retainCount为1,所以person不会释放,dog固然也不会释放,这就是造成循环引用的导致内存泄露的原因!

  • 使用weak
  • delegate-strong
    //person对dog强引用
    
    @property (nonatomic, strong) HWDog *dog; person
    
    //self.dog.delegate只对person弱引用,并未使person的retainCount + 1
    
    @property (nonatomic, weak) id<HWDogDelegate>delegate;
    

    所以当viewController不对person引用后,person的retainCount为0,即person会被释放,那么dog也被释放

    如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注