文档章节

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

木木情深
 木木情深
发布于 2015/06/24 16:38
字数 1437
阅读 31
收藏 0

对象内存的回收


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


定时器的自释放

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

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(onTimerCount) userInfo:nil repeats:YES];

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


KVO的自释放

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


- (void)viewDidLoad {

    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onNotice) name:@"NoticeIdentifier" object:nil];

    [self addObserver:target forKeyPath:@"keyPath" options:NSKeyValueObservingOptionNew context:nil];

}

- (void)dealloc {

    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NoticeIdentifier" object:nil];

    [self removeObserver:target forKeyPath:@"keyPath"];

}

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


[self.KVOController observe:clock keyPath:@"date" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(ClockView *clockView, Clock *clock, NSDictionary *change) {

    clockView.date = change[NSKeyValueChangeNewKey];

}];

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


[self.KVOController observe:self keyPath:@"date" options:NSKeyValueObservingOptionNew block:^(NSDictionary *change) {

    // to do

}];

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


[_objectInfosMap setObject:infos forKey:object];

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


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


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

   // to do

}];

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


[self observe:self keyPath:@"KVOPath" options:NSKeyValueObservingOptionNew callback:^(HTBKVObservation *observation, NSDictionary *changeDictionary) {

   // to do

}];

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


NSNotification的自释放


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


[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidChangeFrameNotification object:nil] subscribeNext:^(id x) {

        // to do

    }

];

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


[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidChangeFrameNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) {

        // to do

    }

];

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


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


动态属性的自释放

@property 的自释放

swizzling dealloc的自释放

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


本文转载自:http://www.cocoachina.com/ios/20150623/12197.html

共有 人打赏支持
上一篇: 音频 API 一览
下一篇: gcc和g++的区别
木木情深
粉丝 37
博文 189
码字总数 26451
作品 0
广州
程序员
私信 提问
ArcGIS for iOS 开发系列(1) – 基本概念

1.1 iOS简介 2006年苹果公司发布了智能手机iPhone,卓越的外形设计和新颖的触摸式交互,令其迅速风靡全球,随后发布的平板电脑iPad同样也取得了巨大成功,二者所搭载的都是iOS智能移动操作系...

长平狐
2012/11/28
867
0
10个优秀Objective-C和iOS开发在线视频教程

如果你自己开发iOS应用,你肯定会发现网上有很多资源。学习编程的一个最好的方法就是自己写代码,而开始写代码的最快的方式就是看其他人怎么写。我们从海量视频和学习网站中整理出了我们认为...

mingxun
2014/05/09
0
0
Somya Jain 谈从 C# 到 Objective-C

几年前掌上电脑很大程度上就是一新奇事物和玩具。但如今,商业界正发生着一场重大变化。许多传统上在XAML,Flex或HTML上编写应用的商业公司突 然发现,iPad应用有着数目巨大的需求。这些需求...

HenryChan
2012/08/08
2.8K
12
iOS 7 开发:设置 Xcode 5 和 iOS 7 SDK

对新的iOS开发者,改变是好的 正如我之前的文章所提及的, iOS 7 代表的不止是苹果改变他们的移动设备的UI;它也代表了对延缓学习怎样开始建立原生iOS应用的开发者的一个机会. iOS 7 是最新的...

oschina
2013/06/19
11K
0
关于Android流畅度不如iOS的几点看法

网上一名据称是前谷歌实习生的人透露了一些关于Android系统硬件加速的内幕。据称,在 Android3.0和4.0之前,并没有完整的硬件加速。他们一直在通过硬件加速绘制某些UI元素,并称效果并不像他...

虫虫
2011/12/17
21.3K
28

没有更多内容

加载失败,请刷新页面

加载更多

C#匿名委托

list自定义排序 //list自定义排序public static List<string> sortList(List<string> m_str,string splitStr) //a b表示列表中的元素{String[] strArray=m_str.ToArray();......

青衣霓裳
16分钟前
3
0
Python 之父退位后,会有新任终身仁慈独裁者吗?怎么产生?

随着 Python 之父 Guido van Rossum 逐步卸任 BDFL,Python(CPython)的未来之路牵动了万千开发者的心。没了首领,Python 今后的发展会怎么样?社区将如何运作?谁来领导 Python 这门语言和...

编辑部的故事
21分钟前
7
0
我的Linux系统九阴真经

在今天,互联网的迅猛发展,科技技术也日新月异,各种编程技术也如雨后春笋一样,冒出尖来了。各种创业公司也百花齐放百家争鸣,特别是针对服务行业,新型互联网服务行业,共享经济等概念的公...

linux-tao
今天
20
0
MySQL: Starting MySQL….. ERROR! The server quit without updating PID file

前段时间打包了一个数据库镜像,但是启动容器之后发现报错 ··· ··· MySQL: Starting MySQL….. ERROR! The server quit without updating PID file 查了网络上的解决方案比较全,遂转帖...

blackfoxya
今天
7
0
C4C销售订单行项目价格维护方法

需求很简单,能够创建销售订单,在行项目里添加产品,带出价格来,同时把总价显示在销售订单抬头区域。 如下图所示: 下面是具体配置。 Business Configuration里,点击Sales Order的配置: ...

JerryWang_SAP
今天
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部