“自释放”在iOS开发中的应用

转载请注明出处:http://www.olinone.com/

今天,跟大家聊聊“自释放”思想在iOS开发中的应用,何为“自释放”?可以简单的理解为对象在生命周期结束后自动清理回收所有与其相关的资源或链接,这个清理不仅仅包括对象内存的回收,还包括对象解耦以及附属事件的清理等,比如定时器的自我停止、KVO对象的监听移除等

对象内存的回收

开发中,对象管理的基本原则——谁创建谁释放。但是,非ARC工程中,我们会用autorelease来标记一个对象,告诉编辑器,这个对象我不负责释放,此时,这个对象就变成了“自释放”对象,当其不再需要时,系统就会自动回收其内存。而ARC工程中,所有对象对于我们来说都是自释放对象,很高兴,我们不再需要处处留意内存泄露的问题,可以把更多的精力放在业务逻辑上,但是这并不意味着真的没有内存泄露,试试这个工具HJNSObjectRelease,也许你会有意想不到的收获。

定时器的自释放

定时器与一般对象不同,当创建完定时器后,其并不会自我释放,需要在适当时刻invalidate。在实际开发中,也许你经常会这样创建定时器

self.timer=[NSTimerscheduledTimerWithTimeInterval:1.0target:selfselector:@selector(onTimerCount)userInfo:nilrepeats:YES];

然后在dealloc函数中将定时器invalidate。很遗憾,你会发现程序永远也不会执行到dealloc函数,因为NSTimer强引用target对象,循环引用的出现必然导致内存泄露。此时,你肯定非常想要一个weak target的定时器,很高兴,MSWeakTimer很好的满足了你的需求。但是,Timer仍然没有自我释放,你仍然需要在dealloc中将其invalidate。那么,如何才能不写invalidate?定时器能否自释放?我们先把这个问题放在一边,接着往下看

KVO的自释放

iOS开发中,经常会用到消息通知及KVO,也许你会这样写代码

-(void)viewDidLoad{

        [superviewDidLoad];

        [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(onNotice)name:@"NoticeIdentifier"object:nil];

        [selfaddObserver:targetforKeyPath:@"keyPath"options:NSKeyValueObservingOptionNewcontext:nil];

}

-(void)dealloc{

        [[NSNotificationCenterdefaultCenter]removeObserver:selfname:@"NoticeIdentifier"object:nil];

        [selfremoveObserver:targetforKeyPath:@"keyPath"];

}

随着时间的积累,你会非常习惯这种写法,并且苹果也是这样推荐的。但是慢慢你会发现所有对象的Dealloc函数都只做了这一件事,能不能不做这件事?FBKVOController也许会是一个不错的选择,Demo可以这样写

[self.KVOControllerobserve:clockkeyPath:@"date"options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNewblock:^(ClockView*clockView,Clock*clock,NSDictionary*change){

         clockView.date=change[NSKeyValueChangeNewKey];

}];

FBKVOController的实现原理可以查看这篇文章,通过自释放的实现,程序猿不再关心remove监听。但是其还是有一定的局限性——对象无法监听自己的属性,如果你的代码是这样的

[self.KVOControllerobserve:selfkeyPath:@"date"options:NSKeyValueObservingOptionNewblock:^(NSDictionary*change){

         // to do

}];

很遗憾,循环引用的问题又出现,因为FBKVOController中的NSMapTable对象会retain key对象,具体代码如下

[_objectInfosMapsetObject:infosforKey:object];

那么,FBKVOController是如何做到自释放的?可以归纳为四个字——动态属性。其为观察者绑定动态属性self.KVOController,动态绑定的KVOController会随着观察者的释放而释放,KVOController在自己的dealloc函数中移除KVO监听,巧妙的将观察者的remove转移到其动态属性的dealloc函数中。

可是,这又有什么用?对象仍然无法监听自己的属性,还是要重写set函数。HTBKVObservation也许会改变你的想法,其和FBKVOController来自同一人,代码可以这样写

self.anObservation=[HTBKVObservationobserve:anObjectToObservekeyPath:@"observeMe"options:0callback:^(HTBKVObservation*observation,NSDictionary*changeDictionary){

       // to do

}];

HTBKVObservation并没用采用动态属性,而是采用属性的方式实现自释放。可以监控对象自己的属性,但是需要创建属性HTBKVObservation。这里我对其做了一点扩展,方便使用,代码可以这样写

[selfobserve:selfkeyPath:@"KVOPath"options:NSKeyValueObservingOptionNewcallback:^(HTBKVObservation*observation,NSDictionary*changeDictionary){

        // to do

}];

FBKVOControllerHTBKVObservation通过属性或动态属性巧妙的将KVO的remove转移给第三者,实现了KVO事件的解耦,为自释放的实现提供了一种借鉴思路

NSNotification的自释放

谈完 KVO,再来谈谈NSNotification。针对Notification,ReactiveCocoa做了很好的封装,网上有很多介绍其如何使用的文章,在此不再累述。直接看代码

[[[NSNotificationCenterdefaultCenter]rac_addObserverForName:UIKeyboardDidChangeFrameNotificationobject:nil]subscribeNext:^(idx){

            // to do

       }

];

简单明了,当观察者dealloc,很遗憾,NSNotification并没用移除,因为对象并没用自释放,正确代码应该是这样

[[[[NSNotificationCenterdefaultCenter]rac_addObserverForName:UIKeyboardDidChangeFrameNotificationobject:nil]takeUntil:self.rac_willDeallocSignal]subscribeNext:^(idx){

             // to do

      }

];

ReactiveCocoa自释放的原理与FBKVOController不同,其并不是通过属性或者动态属性的方式实现,而是通过swizzling观察对象的dealloc函数,在自定义dealloc函数实施清理,但不是默认清理,需要我们告诉它willDeallocSignal的时候完成所有清理工作。

除了定时器、KVO、NSNotification,包括封装的某个功能对象,比如HttpRequest,或者数据库ListSql等,合理的利用自释放可以给使用者带来更多的便利,同时也会减少 crash 产生的概率。实现自释放的方法可以总结为以下三种方式

1、动态属性的自释放

2、@property 的自释放

3、swizzling dealloc的自释放

可以根据具体业务或者设计思想选择对应的实现方式,这是一种思想,更是一个习惯。相信你会爱上它,毕竟谁不喜欢简洁的实现方式了!

后记: 好久没有更新文章,一是最近任务比较重,接手老代码,几千行的Controller实在无能为力,只能重写。如今,面对不到300行的Controller还是挺有成就感。生命不息,折腾不止!二是想为大家分享一点干货,不敢轻易提笔。依旧,记得点赞,感谢大家来访!

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

推荐阅读更多精彩内容