Objective-C高级编程:iOS与OS X多线程和内存管理
自动引用计数
自动引用计数(ARC,Automatic Reference Counting)
“在LLVM编辑器中设置ARC为有效状态,就无需再次键入retain或者是release代码”
引用计数的内存管理
生成对象->持有对象->释放对象->废弃对象
内存管理的思考方式
- 自己生成的对象,自己所持有
- 非自己生成的对象,自己也能持有
- 不在需要自己持有的对象时释放
- 非自己持有的对象无法释放
对象操作与Objective-C方法的对应
对象操作 |
Objective-C方法 |
生成并持有对象 |
alloc/new/copy/mutableCopy等 |
持有对象 |
retain |
释放对象 |
release |
废弃对象 |
dealloc |
Objective-C内存管理方法并不包括在该语言中,而是包含在Cocoa框架中用于iOS、OS X开发。Cocoa框架中Foundation框架类库的NSObject类担负着内存管理的职责。其中alloc/retain/release/dealloc方法分别指的是NSObject类中的alloc类方法,retain实例方法,release实例方法,dealloc实例方法( +alloc、-retain、-release、 -deallc)。
自己生成的对象,自己所持有
- alloc
- new
- copy
- mutableCopy
alloc方法
1 2
| id obj = [[NSObject alloc] init]; //自己生成持有对象
|
new方法
1 2
| id obj = [NSObject new]; //自己生成持有对象
|
copy方法利用基于NSCopying方法约定,由各类实现的copyWithZone:方法生成并持有该对象副本。
mutableCopy方法基于NSMutableCopying方法约定由各类实现的mutableCopyWithZone:方法生成并持有该对象副本。
非自己生成的对象,自己也能持有
这里用NSMutableArray类的array类方法举例:
1 2 3 4 5
| id obj = [NSMutableArray array]; //取得非自己生成的对象,但自己并不持有
[obj retain]; // 自己持有对象
|
通过retain方法使非自己生成的对象成为自己所持有的。
不在需要自己持有的对象时释放
1 2 3 4 5
| id obj = [[NSObject alloc] init]; //自己生成持有对象
[obj release]; //释放对象
|
1 2 3 4 5 6 7 8
| id obj = [NSMutableArray array]; //取得非自己生成的对象,但自己并不持有
[obj retain]; // 自己持有对象
[obj release]; //释放对象
|
用alloc等方法生成并自己持有的对象,用release方法释放
用retain方法持有非自己生成的对象,也用release方法释放
用上面方法持有的对象在不使用时要用release方法释放
ARC规则
所有权修饰符
OC中为了处理对象,可将变量类型定义成id类型或者各种对象类型(指向NSObject这样的的Objective-C类的指针,如NSObject*)。
ARC有效时,id类型和对象类型和C语言其他类型不同,一定要加上所有权修饰符。
- _ _strong 修饰符
- _ _weak 修饰符
- _ _unsafe_unretained 修饰符
- _ _autoreleasing 修饰符
在没有明确指定所有修饰符时默认为_ _strong 修饰符,
_ _strong 修饰符表示对对象的强引用,持有其变量,在超出其作用域时被废弃,随着强引用的消失,引用的对象也会随之释放。
_ unsafe_unretained 修饰符
和weak一样并不能持有对象,所以生成的对象会被立即释放。
在使用 _unsafe_unretained 修饰符时,赋值给附有strong修饰符的变量时要确保被赋值的对象存在。
_ _unsafe_unretained在iOS5在没有引入weak之前使用现在基本不使用了。
关于_ strong和 _weak的区别我觉得下面这篇文章讲的很清楚、更直观,比这本书中讲到要直观很多。
strong和weak
为什么会出现这两种修饰符?
因为 __strong并不能解决内存管理中一些问题,其中就是循环引用、类成员变量的循环引用(互相强引用)、对自身的强引用问题,这些很容易造成内存泄漏,应该废弃的对象在超出其生命周期后继续存在。这时使用 _weak 修饰符就不会造成循环引用。因为使用 _ _weak时并不持有该对象,所以不会出现应该废弃的对象在超出其生命周期后继续存在。
ARC规则
- 不能使用retain/release/retainCount/autorelease
- 不能使用NSAllocateObject/NSDeallocateObject
- 必须遵守内存管理的命名规则
- 不要显示调用dealloc
- 使用@autoreleasepool块替代NSAutoreleasePool;
- 不能使用区域(NSZone)
- 对象型变量不能作为C语言结构体(struct/union)的成员
- 显示转换”id”和”void * “