总结了Effective Objective-C之后,还想读一本进阶的iOS书,毫不犹豫选中了《Objective-C 高级编程》:
这本书有三个章节,我针对每一章节进行总结并加上适当的扩展分享给大家。可以从下面这张图来看一下这三篇的整体结构:
注意,这个结构并不和书中的结构一致,而是以书中的结构为参考,稍作了调整。
本篇是第一篇:引用计数,简单说两句:
Objective-C通过 retainCount 的机制来决定对象是否需要释放。 每次runloop迭代结束后,都会检查对象的 retainCount,如果retainCount等于0,就说明该对象没有地方需要继续使用它,可以被释放掉了。无论是手动管理内存,还是ARC机制,都是通过对retainCount来进行内存管理的。
先看一下手动内存管理:
手动内存管理
我个人觉得,学习一项新的技术之前,需要先了解一下它的核心思想。理解了核心思想之后,对技术点的把握就会更快一些:
内存管理的思想
- 思想一:自己生成的对象,自己持有。
- 思想二:非自己生成的对象,自己也能持有。
- 思想三:不再需要自己持有的对象时释放对象。
- 思想四:非自己持有的对象无法释放。
从上面的思想来看,我们对对象的操作可以分为三种:生成,持有,释放,再加上废弃,一共有四种。它们所对应的Objective-C的方法和引用计数的变化是:
对象操作 | Objecctive-C方法 | 引用计数的变化 |
---|---|---|
生成并持有对象 | alloc/new/copy/mutableCopy等方法 | +1 |
持有对象 | retain方法 | +1 |
释放对象 | release方法 | -1 |
废弃对象 | dealloc方法 | 无 |
用书中的图来直观感受一下这四种操作:
下面开始逐一解释上面的四条思想:
思想一:自己生成的对象,自己持有
在生成对象时,使用以下面名称开头的方法生成对象以后,就会持有该对象:
- alloc
- new
- copy
- mutableCopy
举个??:
id obj = [[NSObject alloc] init];//持有新生成的对象
这行代码过后,指向生成并持有[[NSObject alloc] init]的指针被赋给了obj,也就是说obj这个指针强引用[[NSObject alloc] init]这个对象。
同样适用于new方法:
id obj = [NSObject new];//持有新生成的对象
注意:
这种将持有对象的指针赋给指针变量的情况不只局限于上面这四种方法名称,还包括以他们开头的所有方法名称:
- allocThisObject
- newThatObject
- copyThisObject
- mutableCopyThatObject
举个??:
id obj1 = [obj0 allocObject];//符合上述命名规则,生成并持有对象
它的内部实现:
- (id)allocObject
{
id obj = [[NSObject alloc] init];//持有新生成的对象
return obj;
}
反过来,如果不符合上述的命名规则,那么就不会持有生成的对象,
看一个不符合上述命名规则的返回对象的createObject方法的内部实现??:
- (id)createObject
{
id obj = [[NSObject alloc] init];//持有新生成的对象
[obj autorelease];//取得对象,但自己不持有
return obj;
}
经由这个方法返回以后,无法持有这个返回的对象。因为这里使用了autorelease。autorelease提供了这样一个功能:在对象超出其指定的生存范围时能够自动并正确地释放(详细会在后面介绍)。
也就是说,生成一个调用方不持有的对象是可以通过autorelease来实现的(例如NSMutableArray的array类方法)。
我的个人理解是:通过autorelease方法,使对象的持有权转移给了自动释放池。所以实现了:调用方拿到了对象,但这个对象还不被调用方所持有。
由这个不符合命名规则的例子来引出思想二:
思想二:非自己生成的对象,自己也能持有
我们现在知道,仅仅通过上面那个不符合命名规则的返回对象实例的方法是无法持有对象的。但是我们可以通过某个操作来持有这个返回的对象:这个方法就是通过retain方法来让指针变量持有这个新生成的对象:
id obj = [NSMutableArray array];//非自己生成并持有的对象
[obj retain];//持有新生成的对象
注意,这里[NSMutableArray array]返回的非自己持有的对象正是通过上文介绍过的autorelease方法实现的。所以如果想持有这个对象,需要执行retain方法才可以。
思想三:不再需要自己持有的对象时释放对象
对象的持有者有义务在不再需要这个对象的时候主动将这个对象释放。注意,是有义务,而不是有权利,注意两个词的不同。
来看一下释放对象的例子:
id obj = [[NSObject alloc] init];//持有新生成的对象
[obj doSomething];//使用该对象做一些事情
[obj release];//事情做完了,释放该对象
同样适用于非自己生成并持有的对象(参考思想二):
id obj = [NSMutableArray array];//非自己生成并持有的对象
[obj retain];//持有新生成的对象
[obj soSomething];//使用该对象做一些事情
[obj release];//事情做完了,释放该对象
可能遇到的面试题:调用对象的release方法会销毁对象吗?
答案是不会:调用对象的release方法只是将对象的引用计数器-1,当对象的引用计数器为0的时候会调用了对象的dealloc 方法才能进行释放对象的内存。
思想四:无法释放非自己持有的对象
在释放对象的时候,我们只能释放已经持有的对象,非自己持有的对象是不能被自己释放的。这很符合常识:就好比你自己才能从你自己的银行卡里取钱,取别人的卡里的钱是不对的(除非他的钱归你管。。。只是随便举个例子)。
两种不允许的情况:
您可能想查找下面的文章:
- 《Objective-C高级编程》干货三部曲(一):引用计数篇
- 简单谈谈C++ 头文件系列之(iosfwd)
- 总结IOS中nil、Nil、NULL和NSNull区别
- Cocos2d-x UI开发之CCControlPotentiometer控件类使用实例
- Cocos2d-x UI开发之CCControlSwitch控件类使用实例
- Cocos2d-x UI开发之CCControlColourPicker控件类使用实例
- Cocos2d-x UI开发之CCControlSlider控件类使用实例
- Cocos2d-x UI开发之CCControlButton控件类实例
- iostream与iostream.h的区别详细解析
- 基于ios中的流状态的定义分析