【精品】iOS中关于delegate修饰符深究与论证

研究项目注意到项目中对delegate的修饰都用的是unsafe_unretained.

确实几年前,甚至更早之前的MRC时代用unsafe_unretained以至于后面热门的assign修饰delegate并没有任何争议,甚至还得到推崇。如果爱阅读Apple官方源码的话,就会知道在2016的时候,Apple官方也一直用assign修饰大部分的delegate(注意我为什么说是大部分而不是全部,后面我会解释)

而且当年还在Stack Overflow上引发了关于官方为啥用assign 而不用retain的讨论:
https://stackoverflow.com/questions/918698/why-are-objective-c-delegates-usually-given-the-property-assign-instead-of-retai

原因是它能很好地解决循环引用的问题:
之前常见的delegate往往都是assign方式的属性而不是retain方式的属性,因为赋值不会增加引用计数,就是为了防止delegate两端产生不必要的循环引用。如果一个UITableViewController对象a通过retain获取了UITableView对象b的所有权,已经保持了强引用,而这个UITableView对象b的delegate又是a,如果这个delegate也是retain方式的,那基本上就没有机会释放这两个对象了,就会造成循环引用,进而导致内存泄漏。

而现在再阅读源码,就会发现Apple早已经悄悄的把assign换成了weak。
原因不是因为assign和unsafe_unretained不能解决循环引用的问题,而是他们解决的并不够彻底!
因为声明为assign和unsafe_unretained的指针,虽然不会对对象进行retain,但当对象销毁时,会依然指向之前的内存空间,造成野指针,也就是绝大多数程序有时会出现莫名其妙的小概率崩溃事件原因之一
另一方面当weak修饰的话,它不会对对象进行retain,当对象销毁时,会自动指向nil,完美的避免了野指针问题,相比前者就更干净,彻底。

那么问题就又来了
1.unsafe_unretained真的就不好了么,那为啥很多大开源项目里面还用了它?
因为在MRC时代,当需要修饰对象类型时,MRC时代就会使用unsafe_unretained,而且weak等属性在iOS5才开放,所以为了兼容性的问题,依旧保留了它。

2.既然weak修饰delegate这么优秀,那是不是所有地方都用它修饰delegate就好了?

这也牵扯了为什么我之前说的“Apple也一直用assign修饰大部分的delegate”而并没有说“Apple也一直用assign修饰全部的delegate”的解释

重点来了!
重点来了!
重点来了!

如果你仔细研究Apple源码,你可能就会惊奇地发现一条能推翻我之前全部言论的代码!

在Foundation中的NSURLSession类中,居然官方也用retain修饰delegate:


image.png

之前说的所有操作基本都刻意的防止循环引用,为啥Apple官方还专门在这个类中用retain来修饰delegate?

查阅它的官方注释:
The delegate assigned when this object was created.
This delegate object is responsible for handling authentication challenges, for making caching decisions, and for handling other session-related events. The session object keeps a strong reference to this delegate until your app exits or explicitly invalidates the session. If you do not invalidate the session, your app leaks memory until it exits.
Note
This delegate object must be set at object creation time and may not be changed.
SDKs iOS 7.0+, macOS 10.9+, tvOS 9.0+, watchOS 2.0+
Declared In Foundation
More Property Reference

里面值得重点关注的地方,大概翻译是“会话对象保持对该委托的强引用,直到应用程序退出或显式地使会话无效。如果你没有使会话失效,你的应用程序会泄露内存直到它退出。”

细细品味,就能深悟“意料之外,情理之中”这句话
个人理解是因为NSURLSession类是网络接口类,而用retain修饰delegate是为了保证后台网络请求的稳定性,如下载,保证后台下载不会轻易被系统释放掉!
当然不需要后台下载,也要按照apple官方注释中强调的一定要去取消,要去注意释放session,不然会造成leaks memory

除此之外,在Apple的官方源码中还有一些这样强引用的delegate,如:


image.png

查阅它的官方注释:
Specifies the receiver’s delegate object.
Defaults to nil.
Important
The delegate object is retained by the receiver. This is a rare exception to the memory management rules described in Advanced Memory Management Programming Guide.
An instance of CAAnimation should not be set as a delegate of itself. Doing so (outside of a garbage-collected environment) will cause retain cycles.
SDKs iOS 2.0+, macOS 10.5+, tvOS 9.0+
Declared In Core Animation
More Property Reference

为啥这里也用strong修饰delegate?

Apple的解释也很有趣
“The delegate object is retained by the receiver. This is a rare exception to the memory management rules described in Advanced Memory Management Programming Guide.”
意思是“它就是个内存管理规则比较罕见的特例!”

个人理解是因为CAAnimation类是动画类,就动画来说都不是单独存在的,它必须要依赖于能展示动画的母体,所以他的生命周期是依赖于layer->view的生命周期的,需要特定的设置展示与释放,比较罕见,所以用强引用保证可靠性。

综上所诉,编程是一个很神奇的东西,可能在现在看某些操作很合乎情理,但估计过段时间它就会被质疑。当然在另一方面,只要对代码理解透彻,可能一些骚操作也会带来很大的收益,这就是编程的魅力吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容