一、计数器
(一)、引用计数器的基本操作
1、 方法的基本使用
① retain :计数器+1,会返回对象本身 ② release :计数器-1,没有返回值 ③ retainCount :获取当前的计数器 ④ dealloc * 当一个对象要被回收的时候,就会调用 * 一定要调用[super dealloc],这句调用要放在最后面1 #import "Person.h" 2 3 @implementation Person 4 5 6 // 当一个Person对象被回收的时候,就会自动调用这个方法 7 - (void)dealloc 8 { 9 NSLog(@"Person对象被回收");10 11 // super的dealloc一定要调用,而且放在最后面12 [super dealloc];13 }14 15 @end
2、 概念 ① 僵尸对象 :所占用内存已经被回收的对象,僵尸对象不能再使用 ② 野指针 :指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS) ③ 空指针 :没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
3、代码举例
1 #import2 #import "Person.h" 3 4 int main() 5 { 6 // 1 7 Person *p = [[Person alloc] init]; 8 9 //NSUInteger c = [p retainCount];10 11 //NSLog(@"计数器:%ld", c);12 13 14 // 2 retain方法返回的是对象本身15 [p retain];16 17 // 118 [p release];19 20 // 0 野指针:指向僵尸对象(不可用内存)的指针21 [p release];22 23 [p retain];24 25 // -[Person setAge:]: message sent to deallocated instance 0x100109a1026 // 给已经释放的对象发送了一条-setAge:消息:27 p.age = 10;28 //[p setAge:10];29 30 // 指针p变成空指针31 //p = nil;32 33 // EXC_BAD_ACCESS : 访问了一块坏的内存(已经被回收、已经不可用的内存34 // 野指针错误35 // OC不存在空指针错误,给空指针发送消息,不报错36 [p release];37 [p release];38 [p release];39 [p release];40 41 [nil release];42 43 return 0;44 }
(二) 多个对象之间的内存管理
1、 你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作)
2、 你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release) 3、 谁retain,谁release 4、 谁alloc,谁release1 // b-1 2 Book *b = [[Book alloc] init]; 3 // p-1 4 Person *p1 = [[Person alloc] init]; 5 6 //p1想占用b这本书 7 // b-2 8 [p1 setBook:b]; 9 10 // p-011 // b-112 [p1 release];13 p1 = nil;14 15 // b-016 [b release];17 b = nil;
(三)、set方法的内存管理
1、内存管理代码规范:
① 只要调用了alloc,必须有release(autorelease) ② 对象不是通过alloc产生的,就不需要release2、set方法
① 代码规范实现
1 //基本数据类型:直接复制 2 - (void)setAge:(int)age 3 { 4 _age = age; 5 } 6 7 // OC对象类型 8 - (void)setCar:(Car *)car 9 {10 // 1.先判断是不是新传进来对象11 if ( car != _car )12 {13 // 2.对旧对象做一次release14 [_car release];15 16 // 3.对新对象做一次retain17 _car = [car retain];18 }19 }
3、dealloc方法的代码规范实现
1 //一定要[super dealloc],而且放到最后面2 // 对self(当前)所拥有的其他对象做一次release3 - (void)dealloc4 {5 [_car release];6 [super dealloc];7 }
(四) @property参数
1、 控制set方法的内存管理
*retain : release旧值,retain新值(用于OC对象)
// retain : 生成的set方法里面,release旧值,retain新值@property (retain) Book *book;@property (retain) NSString *name;
*assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
@property ( assign) int height;
*copy : release旧值,copy新值(一般用于NSString *)
2、控制生成或者不生成set方法
*readwrite :同时生成set方法和get方法(默认)
*readonly :只会生成get方法
@property (readwrite, assign) int height;
3、多线程管理
*atomic :性能低(默认)
*nonatomic :性能高
@property (nonatomic, assign, readwrite) int weight;
4、控制set方法和get方法的名称
*setter : 设置set方法的名称,一定有个冒号:
*getter : 设置get方法的名称
// 返回BOOL类型的方法名一般以is开头@property (getter = isRich) BOOL rich;
(五) 循环引用
1、 @class
① 作用:仅仅告诉编译器,某个名称是一个类
② 开发中引用一个类的规范 *在.h文件中用@class来声明类1 #import2 #import "Card.h" 3 // @class仅仅是告诉编译器,Card是一个类 4 //@class Card; 5 6 @interface Person : NSObject 7 8 @property (nonatomic, retain) Card *card; 9 10 @end
* 在.m文件中用#import来包含类的所有东西
1 #import "Person.h" 2 #import "Card.h" 3 4 @implementation Person 5 6 - (void)dealloc 7 { 8 NSLog(@"Person被销毁了"); 9 [_card release];10 11 [super dealloc];12 }13 14 @end
2、循环retain
①问题*A对象retain了B对象,B对象retain了A对象
*这样A、B对象永远无法释放
②两端循环引用解决方案
* 一端用retain * 一端用assign (六)、 autorelease1、autorelease的基本用法
① 会将对象放到一个自动释放池中 ② 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作 ③ 会返回对象本身 ④ 调用完autorelease方法后,对象的计数器不变 2、autorelease的好处 ① 不用再关心对象释放的时间 ② 不用再关心什么时候调用release 3、autorelease的使用注意 ① 占用内存较大的对象不要随便使用autorelease ② 占用内存较小的对象使用autorelease,没有太大影响 4、错误写法 ① alloc之后调用了autorelease,又调用release1 @autoreleasepool2 {3 // 14 Person *p = [[[Person alloc] init] autorelease];5 6 // 07 [p release];8 }9
② 连续调用多次autorelease
1 @autoreleasepool2 {3 Person *p = [[[[Person alloc] init] autorelease] autorelease];4 }
5、自动释放池
① 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)② 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
6、自动释放池的创建方式
@autoreleasepool { }
7、代码举例
1 void test() 2 { 3 @autoreleasepool 4 { // { 开始代表创建了释放池 5 6 // autorelease方法会返回对象本身 7 // 调用完autorelease方法后,对象的计数器不变 8 // autorelease会将对象放到一个自动释放池中 9 // 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作10 Person *p = [[[Person alloc] init] autorelease];11 12 p.age = 10;13 14 15 16 @autoreleasepool17 {18 // 119 Person *p2 = [[[Person alloc] init] autorelease];20 p2.age = 10;21 22 23 }24 25 26 Person *p3 = [[[Person alloc] init] autorelease];27 28 29 } // } 结束代表销毁释放池30 }