一、autorelease
1、自动释放池
(1) 在iOS程序运行过程中,会创建多个自动释放池。这些池子都是以栈结构存在(栈的特点先进后出)
(2) 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
2、autorelease的基本用法
(1)在给某个对象发送一条autorelease消息时,会将对象放到一个自动释放池中
(2) 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作,并返回对象本身
(3)调用完autorelease方法后,对象的计数器不变
3、自动释放池的创建方式
(1) iOS 5.0前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // 开始
[pool release]; // 结束
结束句还可以写作[pool drain];
(2)iOS 5.0 开始
@autoreleasepool
{ // 以{ 开始,代表创建了释放池
} // 以} 结束,代表销毁释放池
(3)创建多个自动释放池
示例:
@autoreleasepool
{
Person *p = [[[Person alloc] init] autorelease];
p.age = 10;
@autoreleasepool
{
<span style="white-space:pre"> </span>Person *p2 = [[[Person alloc] init] autorelease];
<span style="white-space:pre"> </span>p2.age = 10;
}
Person *p3 = [[[Person alloc] init] autorelease];
}
autorelease实际上只是把对release的调用延迟了,对于每一次autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调 用Release
4、autorelease的好处
(1)不用再关心对象释放的时间
(2)不用再关心什么时候调用release
5、autorelease的使用注意
(1)占用内存较大的对象不要随便使用autorelease
(2)占用内存较小的对象使用autorelease,没有太大影响
6、错误写法
(1)alloc之后调用了autorelease,又调用release
示例:
@autoreleasepool
{
Person *p = [[[Person alloc] init] autorelease];
[p release];
}
(2)连续调用多次autorelease
@autoreleasepool
{
Person *p = [[[[Person alloc] init] autorelease] autorelease];
}
7、补充
1.系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的
2.开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
(1) 创建对象时不要直接用类名,一般用self
+ (id)person
{
return [[[self alloc] init] autorelease];
}
(2)一般可以为类添加一个快速创建对象的类方法
+ (id)book
{
return [[[Bookalloc] init] autorelease];
}
外界调用[Bookbook]时,根本不用考虑在什么时候释放返回的Book对象
二、ARC
1、ARC简介
(1)ARC是Automatic Reference Counting(自动引用计数)的简称,自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain、release、autorelease语句,不再需要担心内存管理问题。
(2)ARC 是编译器特性,而不是 iOS 运行时特性,它也不是类似于其它语言中的垃圾收集器。因此 ARC 和手动内存管理性能是一样的,有时还能更加快速,因为编译器还可以执行某些优化
2、ARC的判断准则
(1)规则:只要没有强指针指向对象,就会释放对象
(2)指针分类
a) 强指针:__strong 默认情况下,所有的指针都是强指针
b) 弱指针:__weak 弱指针指向的对象被回收后,弱指针会自动变为nil指针
3、ARC使用注意
(1)不允许调用release、retain、retainCount
(2)允许重写dealloc,但是不允许调用[super dealloc]
(3)@property的参数
- strong :成员变量是强指针(适用于OC对象类型)
- weak :成员变量是弱指针(适用于OC对象类型)
- assign : 适用于非OC对象类型
(4) 以前的retain改为用strong
三、循环引用
1、场景示例
对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类。
示例:
#import "Card.h"
@interface Person : NSObject
@property (nonatomic,retain) Card *card;
@end
#import "Person"
@interface Card : NSObject
@property (nonatomic,retain) Person *person;
@end
以上代码编译会报错,而且会导致两个对象永远无法释放
2、解决方法
(1)在.h文件中用@class来声明类,在.m文件中用到对象时再使用#import来包含类的所有东西
(2)一端用retain,一端用assign
示例
@class Card.h
@interface Person : NSObject
@property (nonatomic,retain) Card *card;
@end
@class Person
@interface Card : NSObject
@property (nonatomic,assign) Person *person;
@end
- 当使用@class在两个类相互声明,就不会出现编译报错
- 一端用retain一端用assign,不会出现内存泄露
3、@class和#import的区别
(1)#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在.h文件只是类的声明
(2)如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率非常低,而相对来讲,使用@class方式就不会出现这种问题了
(3)在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类
4、ARC模式下循环引用
一端用strong,另一端用weak,用@class来声明类
示例
@class Card.h
@interface Person : NSObject
@property (nonatomic,strong) Card *card;
@end
@class Person
@interface Card : NSObject
@property (nonatomic,weak) Person *person;
@end