Objective-C中的内存管理,也就是引用计数。可以用开关房间的灯为例来说明引用计数的机制。
假如办公室里的照明设备只有一个。上班进入办公室的人需要照明,所以要把灯打开。而对于下班离开办公室的人来说,已经不需要照明了,所以要把灯关掉。
解决这一问题的办法是使办公室在还有至少1人的情况下保持开灯状态,而在无人时保持关灯状态。
为判断是否还有人在办公室里,这里导入计数功能来计算“需要照明的人数”。
这样就能在不需要照明的时候保持关灯状态。办公室中仅有的照明设别得到了很好的管理。
在Objective-C中,“对象”相当于办公室的照明设备。在显示世界中办公室的照明设备只有一个,但在OCzhong ,可以同时处理好多对象。
对照明设备所做的动作 | 对OC对象所做的动作 | OC对应的方法 |
---|---|---|
开灯 | 生成对象 | alloc/new/copy/mutableCopy等方法 |
需要照明 | 持有对象 | retain方法 |
不需要照明 | 释放对象 | release方法 |
关灯 | 废弃对象 | dealloc方法 |
正确的思考方式是:
Cocoa框架中Foundation框架类库的NSObject类负担内存管理的指责。OC内存中的alloc/retain/release/dealloc方法分别只带NSObject类的alloc类方法,retain实例方法,release实例方法和dealloc实例方法。
自己生成的对象,自己持有
使用以下名称开头的方法名意味这自己生成的对象只有自己持有:
注:自己指 对象的只用环境
例如:
- /*
- * 自己生成并持有对象
- */
- id obj = [[NSObject alloc] init];
- // id obj = [NSObject new];
- /*
- * 自己持有对象
- */
使用NSObject类的alloc类方法就能自己生成并持有对象。只想生成并持有对象的指针被赋给变量obj。另外new类方法也可以。
copy方法利用基于NSCopying方法约定,由各类实现的copyWithZone:生成并持有对象的副本。与copy方法类似,mutableCopy方法利用给予NSMutableCopying方法约定,由各类实现的mutableCopyWithZone:方法生成并持有对象的副本。两者的区别在于,copy方法生成不可变更的对象,而mutableCopy方法生成可变更的变量。
非自己生成的对象,自己也能持有
用上述项目之外的方法缺的对象,因为非自己生成并持有,所有自己不是该对象的的持有者。例如NSArray类的array类方法。
- /*
- * 取得非自己生成并持有的对象
- */
- id obj = [NSMutableArray array];
- /*
- * 对象已存在,但自己不持有对象
- */
- [obj retain];
- /*
- * 自己持有对象
- */
代码中,NSMutableArray对象被赋给变量obj,但obj自己并不持有该对象。使用retain方法可以持有对象。
不再需要自己持有的对象时释放
自己持有的对象,一旦不再需要时,持有这有义务释放该对象。释放使用release方法。
- /*
- * 自己生成并持有的对象
- */
- id obj = [NSObject new];
- /*
- * 自己持有对象
- */
- [obj release];
- /*
- * 自己释放对象
- * 只想对象的指针仍然被保留在变量obj中,貌似能够访问,但对象一经释放绝对不可访问
- */
用alloc/new方法由自己生成并持有的对象就通过release方法释放了。自己生成而非自己所持有的对象,若用retain方法变为自己持用,也同样用release方法释放。
如果要用某个自定义方法生成对象,并将其返回给该方法的调用方,那么代码如下:
- - (id) allocObject {
- /*
- * 自己生成并持有对象
- */
- id obj = [[NSObject alloc] init];
- /*
- * 自己持有对象
- */
- return obj;
- }
如上所示,原封不动第返回用alloc方法生成并持有的对象,就能让调用方法也持有该对象。请注意该方法的命名规则,是以alloc开头命名的,那么自定义方法中,以alloc/new/copy/mutableCopy命名的方法,也意味自己生成并持有对象。
- /*
- * 取得非自己生成并持有对象
- */
- id obj1 = [obj0 allocObject];
- /*
- * 自己持有对象
- */
类似于[NSMutableArray array]的自定义方法如下(命名不能以alloc/new/copy/mutableCopy开头)
- - (id) Object {
- id obj = [[NSObject alloc] init];
- /*
- * 自己持有对象
- */
- [obj autorelease];
- /*
- * 取得对象的存在,但自己不持有对象
- */
- return obj;
- }
- id obj1 = [obj0 Object];
- /*
- * 取得的对象存在,但不自己持有
- */
- [obj1 retain];
- /*
- * 自己持有对象
- */
上述方法中,使用了autorelease方法。用该方法,可以使取得的对象存在,但不自己持有。autorelease方法提供使对象在超出的生存范围时能够自动并正确的释放。
无法释放非自己持有的对象
对于用alloc/new/copy/mutableCopy方法生成并持有的对象,或是用retain方法持有的对象,由于持有者是自己,所以在不需要该对象的时候需要将其释放。而由此意外所得到的对象绝对不能释放。如果强行释放,则会造成crash。
- /*
- * 自己生成并持有对象
- */
- id obj = [NSObject new];
- /*
- * 自己持有对象
- */
- [obj release];
- /*
- * 对象已释放
- */
- [obj release];
- /*
- *对象释放后再次释放已非自己持有的对象,导致crash
- */
- id obj1 = [obj0 Object];
- /*
- * 取得的对象存在,但不自己持有
- */
- [obj1 release];
- /*
- * 释放了非自己持有的对象,导致crash
- */
以上,就是“引用计数式内存管理”的思考方式。
来源: https://juejin.im/post/5a24e65c6fb9a044fd1197f4