美文网首页iOS专题资源__系统知识点iOS Review内功修炼
iOS 代理为啥要用weak修饰? (刨根问底一)

iOS 代理为啥要用weak修饰? (刨根问底一)

作者: 汉斯哈哈哈 | 来源:发表于2015-08-14 16:55 被阅读17817次

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

    功能实现就行了,考虑这么多干嘛~~~我只能哈哈哈

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

    可能你还不太理解,没关系,下面先举例,看结果,再分析!

    举例

    • HSDog类

    HSDog.h:

    @protocol HSDogDelegate <NSObject>
    @end
    
    @interface HSDog : NSObject
    
    @property (nonatomic, weak) id<HSDogDelegate>delegate;
    
    @end
    

    HSDog.m:

    #import "HSDog.h"
    
    @implementation HSDog
    
    - (void)dealloc
    {
        NSLog(@"HSDog----销毁");
    }
    
    @end
    
    • HSPerson类

    HSPerson.h:

    @interface HSPerson : NSObject
    
    @end
    

    HSPerson.m:

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

    结果

    • weak修饰代理
    @property (nonatomic, weak) id<HSDogDelegate>delegate;
    

    运行->打印

    HSPerson----销毁
    HSDog----销毁
    
    • strong修饰代理
    @property (nonatomic, strong) id<HSDogDelegate>delegate;
    

    运行->打印
    ....并未打印,说明HSPerson、HSDog对象没调用dealloc方法,两个对象未销毁
    这也是我们经常说的内存泄露,该释放的内存并未释放!

    分析

    • 使用strong

    person对dog强引用

    @property (nonatomic, strong) HSDog *dog; person
    

    self.dog.delegate又对person强引用,使person的retainCount + 1

    @property (nonatomic, strong) id<HSDogDelegate>delegate;
    

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

    • 使用weak

    person对dog强引用

    @property (nonatomic, strong) HSDog *dog; person
    

    self.dog.delegate只对person弱引用,并未使person的retainCount + 1

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

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

    文章同步到微信公众号:hans_iOS 有疑问可以在公众号里直接发

    相关文章

      网友评论

      • 英俊神武:不能写个demo吗
        龙子陵:人家都写得这么明白了还要demo?
      • Levi段玉磊:如果经常循环引用导致iOS内存泄漏,这样的话,我们有其他方法来排查内存泄漏么?我能想到的就是通过每个页面打印 dealloc 日志。
        胖子程:静态分析Analyze、Instrument、MLeaksFinder各种手段可以查到
      • Cocoa丶:@汉斯 你好,之前看过你的几篇文章。今天遇到你说,或者大多说人都说用strong修饰代理是会造成循环引用!但是据我所看到的用strong修饰代理的地方出现在:AFNetWorking,还有一些苹果的官方库(具体什么库,我给忘记了),在此我并非无的放矢,只是暂时还没搞明白为什么会有如此现象。希望能与你一起探讨。
      • ce70df11c8e3:兄弟,写得好 我顶你
      • Accepted_:有个小小的笔误

        举例

        HSDog类
        HSDog.h:
        HSDog.m: 这里写成了HSPerson.m啦
        汉斯哈哈哈:@牛序序 :smile:
        Accepted_:@汉斯哈哈哈 :blush: 主要比较菜,需要一行一行一句一句的读 哈哈
        汉斯哈哈哈:@牛序序 这都被你发现:relaxed:
      • 3e8eb14bdf82:写得真好,没白看
      • sea777777:感谢分享
      • wokenshin:我想问一下,如果我的一类是用的单例呢?这种情况下 使用weak 和 strong有什么区别吗?
      • bing_feng_lv:只要搞懂了set方法是怎么赋值的,也就能分析出循环引用产生的原因
      • 8a44cbc27446:// 实例化person, self对person弱引用,person的retainCount不变
        HSPerson *person = [[HSPerson alloc] init];
        为什么说是弱引用呢,这里都没有用到self.person之类的啊
      • wg689:看明白了 不错
      • 古斯比德:赞一下好文,好好学习了:clap::clap::+1:
        汉斯哈哈哈:@古斯比德 :smile:
      • 80c9a4518c6f:又有了进一步了解
      • 08e367b3e25e:谢谢分享
      • 韦韦韦:若果 dog 不是一个强引用呢(不是设置代理的属性)?是不是不需要weak了。
        handyTOOL:@韦韦韦 dog如果是weak,new完就会被释放了:grin:
      • doubleJJ:第一遍看不是很理解,看第二次就明白了,感谢分享
      • 超_iOS:那么请教楼主,何时用assin何时用weak啊,我一般都用的assin
        汉斯哈哈哈:@李二超 不同点:

        1.weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。

        2.assigin 可以用非 OC 对象,而 weak 必须用于 OC 对象
        来自:微博iOS程序犭袁
      • TIME_for:用assgin,和用weak修饰delegate有什么区别呢?
        HenryCheng:@Toyun :grin: :grin: :grin:
        TIME_for:@HenryCheng OK,明白了,Thanks~~
        HenryCheng:@Toyun assign是指针赋值,不对引用计数进行操作,如果使用完毕以后,不把其置为nil,就有可能产生野指针,这时候如果操作不会crash,而weak使用完就没有了,所以weak更安全,其他也没啥区别
      • Somerr态:强迫症还是要说一下,最后一张图的weak弱引用Person还是要画个虚线箭头😂
      • 7cd363b098c9:强迫症还是要说一下,最后一张图的weak弱引用Person还是要画个虚线箭头😂
      • 7cd363b098c9:好文章,多谢分享!
      • 麦子_today:好文章,感谢分享
      • 75040dae73e8:哥们辛苦了,这个东西学的时候一直没闹懂,刚刚在地铁上花了15分钟懂了,谢谢分享。
        汉斯哈哈哈:@C己 加油:grin:
      • 自由在心:苹果h文件里都是使用assign修饰,那么问题来了,使用weak 和assign 有什么区别? weak修饰的对象释放后其所修饰的变量会被置为nil, 而assign 好像什么也不会做只是简单的赋值,也就是说assgin修饰的变量指针还是指向那个地址(不管这个地址空间的对象是否释放),那么这样assign修饰的delegate 不是更不合理吗?可apple是这样用,有其它别的考虑吗?
        986d14688d75:@SunT_孙涛 这是我们15期的涛桑么 :smiley:
        自由在心:@SunT_孙涛 你说的我知道,只是在疑问苹果API里的delegate是用assign的原因,现在的delegate已经改成weak了,苹果遗留问题。
        HQQ_哈球球:@自由在心 assgin 在引用计数=0 的时候,不会自动置为nil . weak 会自动置为nil
      • 天下无贼:说的确实很容易懂,很赞的文章
      • 8d7e10a4eeee:讲解得挺精辟的 看了以后我懂了
      • 康大侠:HSPerson *person = [[HSPerson alloc] init];这个是强引用,ARC自动release了,alloc会使得引用计数加一
        GerryZhu:@康大侠 你确定 不是 alloc、copy、new?
        然然啊:@康大侠 请问下为啥这个是强引用呢?就是不明白这里
      • eb3179e35abc:其实就是循环引用的问题
        buzaixian程序员:怎么个循环引用呢?了解一下:heart_eyes:
        十一岁的加重:@eb3179e35abc 四字概括全文,经典
      • e5b69d879f27:关注一下,搞Android的,最近开始学习iOS,看到这一块儿了也是不懂,看了你的还是不是太懂,先收藏了吧。另外问问,是不是现在的项目都是使用arc了呀
        汉斯哈哈哈:@简约书适 嗯,新项目基本都用arc
      • ba08449e08cf:虽然看不懂,为你的用心和专业点赞。😋
        汉斯哈哈哈:@丘丘123 谢谢 :stuck_out_tongue_winking_eye:

      本文标题:iOS 代理为啥要用weak修饰? (刨根问底一)

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