OC内存管理
2015-03-11 18:22
218 查看
一、OC内存管理
1、管理范围:任何继承了NSObject的对象,对基本数据类(int、char、float、double、struct、enum等)无效
2、每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象,每个OC对象内部专门有4个字节的存储空间来存储引用计数器
3、当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1,当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出
4、引用计数器的操作
1>.给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
2>.给对象发送一条release消息,可以使引用计数器值-1
3>.可以给对象发送retainCount消息获得当前的引用计数器值
5、对象的销毁
1>.当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
2>.当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
3>.一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
4>.一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
5>.不要直接调用dealloc方法
6>.一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)
野指针:指向该僵尸对象的指针就是野指针
空指针:没有指向任何对象(存储的东西是nil、NULL、0)
6、多对象内存管理
1.谁创建,谁release,如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease,换句话说,不是你创建的,就不用你去[auto]release
2.谁retain,谁release,只要你调用了retain,无论这个对象是如何生成的,你都要调用release
3、总结,有始有终,有加就有减,曾经让对象的计数器+1,就必须在最后让对象计数器-1
2>.你不想再使用某个对象,就让对象的计数器-1
3>.谁使用谁retain,谁release
7、内存管理代码规范
1>.只要调用了alloc就必须要有release,只要对象不是通过alloc产生的舅不需要release
2>.set方法的代码规范
基本数据类型,直接复制 :_age=age;
OC对象类型
一定要[super dealloc]放最后面
对self(当前)所拥有的其他对象做一次realease
只需要在@interface里面写
@property(retain) Bool *book;//对象类型变量可以直接这样写
在@implementation里面写dealloc
1.内存管理相关的参数
retain:release旧值,retain新值(是对象就用retain)
assign:直接赋值(默认,不是对象就用)
copy:release旧值,copy新值
2.是否要生成set方法
readwrite:同时生成setter和getter方法的声明和实现
readonly:只会生成getter的声明和实现
3.多线程管理
nonatomic:性能高
atomic:性能低(默认)
4.setter和getter方法的名称
@property(setter = setA:,getter = adc) int weight
set方法的名称就是setA:,get方法的名称就是adc
返回BOOL类型的方法名一般以is开头,例:
@property(getter = isRich) BOOL rich;
模型设计练习
姓名、微博号码、密码、头像、性别、手机、生日
微博内容、微博配图、发送时间、微博发送人、转发的微博、被评论数、被转发数
1.使用场景:对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类
2.格式:
@class + Card//@class仅仅是告诉编译器,Card是一个类
3.在实际开发中引用类的规范
1>.在.h文件中用@class来声明类
2>.在.m文件中用#import来包含类的所有东西
4.@class和#import的区别
1>.#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息
2>.如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方式就不会出现这种问题了,在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类
3>.两端循环引用(无法释放对象)解决方案:一端用retain,一端用assign
9、autorelease方法基本使用
1>.autorelease方法会返回对象本身,会将对象放到一个自动释放池,例:Person *p = [[[Person alloc] init] autorelease];调用autorelease方法后,对象计数器不变,不会-1,只有当自动释放池被销毁时,会对池子里面所有对象做一次release操作
2>.在实际开发中需要精确控制对象内存管理、对于占用内存较大的对象,不要随便用autorelease方法
3>.在IOS程序运行过程中,会创建无数个池子,这些池子都是以栈的结构存在,当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
说明:系统自带的方法里面没有包含alloc\new\copy,说明返回的对象都是autorelease的,在开发中经常会提供一个类方法,快速创建一个已经autorelease过的对象,创建对象时不要直接使用类名,一般用self,例:
1、计数器的基本操作
1> retain : +1
2> release :-1
3> retainCount : 获得计数器
2、set方法的内存管理
1> set方法的实现
1> OC对象类型
@property (nonatomic, retain) 类名 *属性名;
@property (nonatomic, retain) Car *car;
@property (nonatomic, retain) id car;// 被retain过的属性,必须在dealloc方法中release属性
@property (nonatomic, assign) 类型名称 属性名;
@property (nonatomic, assign) int age;
4、autorelease
1.系统自带的方法中,如果不包含alloc、new、copy,那么这些方法返回的对象都是已经autorelease过的[NSString stringWithFormat:....];[NSDate date];
2.开发中经常写一些类方法快速创建一个autorelease的对象* 创建对象的时候不要直接使用类名,用self
1、管理范围:任何继承了NSObject的对象,对基本数据类(int、char、float、double、struct、enum等)无效
2、每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象,每个OC对象内部专门有4个字节的存储空间来存储引用计数器
3、当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1,当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出
4、引用计数器的操作
1>.给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
2>.给对象发送一条release消息,可以使引用计数器值-1
3>.可以给对象发送retainCount消息获得当前的引用计数器值
5、对象的销毁
1>.当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
2>.当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
3>.一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
4>.一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
5>.不要直接调用dealloc方法
6>.一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)
#import "Person.h" @implementation -(void)dealloc{ NSLog(@"Person对象被回收"); [super dealloc];//super的dealloc一定要调用,而且放最后面 } @end #import <Foudation/Foudation.h> #import "Person.h" int main(){ Person *p = [[Person alloc] init]; NSUInteger c = [p retainCount]; NSLog(@"计数器:%d",c); [p retain]; //retain方法返回对象本身,计数器的值+1=2 [p release]; //计数器的值-1=1 [p release]; //计数器的值-1=0,对象被回收,这时的指针p就是野指针,指向僵尸对象(不可用内存) p = nil; //nil=0,所以把p=0,p变为空指针,OC里面不存在空指针错误 [p release];//EXC_BAD_ACCESS:访问了一块坏的内存(已被回收,不可用),野指针错误 return 0; }僵尸对象:对象的计数器指针为0,所占内存被回收,不能再使用,这样的对象就叫僵尸对象
野指针:指向该僵尸对象的指针就是野指针
空指针:没有指向任何对象(存储的东西是nil、NULL、0)
6、多对象内存管理
1.谁创建,谁release,如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease,换句话说,不是你创建的,就不用你去[auto]release
2.谁retain,谁release,只要你调用了retain,无论这个对象是如何生成的,你都要调用release
3、总结,有始有终,有加就有减,曾经让对象的计数器+1,就必须在最后让对象计数器-1
#import <Foudation/Foudation.h> @interface Book : NSObject{ int _price } -(void)setPrice:(int)price; -(int)price; @end #import "Book.h" @implementation Book -(void)setPrice:(int)price{ _price = price; } -(int)price{ return _price; } -(void)dealloc{ NSLog(@"Book对象被回收"); [super dealloc]; } @end #import <Foudation/Foudation.h> #import "Book.h" @interface Person : NSObject{ Book *_book } -(void)setBook:(Book *)book; -(Book *)book; @end #import "Person.h" @implementation Person -(void)setBook:(Book *)book{ if(car != _car){//判断对象是不是新对象 [_book release];//对当前使用的旧书做一次release _book = [book retain];//book的计数器+1 } } -(Book *)book{ return _book; } -(void)dealloc{ [_book release]; NSLog(@"Person对象被回收"); [super dealloc]; } @end #import <Foudation/Foudation.h> #import "Book.h" #import "Person.h" int main(){ Book *b = [[Book alloc] init];//b=1 Person *p1 = [[Person alloc] init];p=1 [p1 setBook:b];//p1想用这本书,调用Person的setBook方法b=2 [b release];//只要有alloc就有一个release,计数器b-1=1 b = nil;*b指针置空 [p1 release];//调用Person的dealloc操作,b=0 p1 = nil; return 0; }1>.你想使用某个对象,就让对象的计数器+1(让对象做一次retain操作)
2>.你不想再使用某个对象,就让对象的计数器-1
3>.谁使用谁retain,谁release
7、内存管理代码规范
1>.只要调用了alloc就必须要有release,只要对象不是通过alloc产生的舅不需要release
2>.set方法的代码规范
基本数据类型,直接复制 :_age=age;
OC对象类型
-(void)setBook:(Book *)book{ if(car != _car){//先判断传进来的对象是不是新对象 [_book release];//对当前使用的旧对象做一次release _book = [book retain];//对新对象做一次retain,计数器+1 } }3>.dealloc方法代码规范
一定要[super dealloc]放最后面
对self(当前)所拥有的其他对象做一次realease
-(void)dealloc{ [_book release]; NSLog(@"Person对象被回收"); [super dealloc]; }4>.@property(里面的参数)
只需要在@interface里面写
@property(retain) Bool *book;//对象类型变量可以直接这样写
在@implementation里面写dealloc
1.内存管理相关的参数
retain:release旧值,retain新值(是对象就用retain)
assign:直接赋值(默认,不是对象就用)
copy:release旧值,copy新值
2.是否要生成set方法
readwrite:同时生成setter和getter方法的声明和实现
readonly:只会生成getter的声明和实现
3.多线程管理
nonatomic:性能高
atomic:性能低(默认)
4.setter和getter方法的名称
@property(setter = setA:,getter = adc) int weight
set方法的名称就是setA:,get方法的名称就是adc
返回BOOL类型的方法名一般以is开头,例:
@property(getter = isRich) BOOL rich;
模型设计练习
姓名、微博号码、密码、头像、性别、手机、生日
#import <Foundation/Foundation.h> typedef enum { SexMan, // 男 SexWoman // 女 } Sex; typedef struct { int year; int month; int day; } Date; @interface User : NSObject @property (nonatomic, retain) NSString *name;//一定要带上nonatomic提高效率 @property (nonatomic, retain) NSString *account; @property (nonatomic, retain) NSString *password;//http://weibo.com/a.png URL @property (nonatomic, retain) NSString *icon; @property (nonatomic, assign) Sex sex; @property (nonatomic, retain) NSString *phone; @property (nonatomic, assign) Date birthday; @end
#import "User.h" @implementation User - (void)dealloc{ [_name release]; [_account release]; [_icon release]; [_password release]; [_phone release]; [super dealloc]; } @end
微博内容、微博配图、发送时间、微博发送人、转发的微博、被评论数、被转发数
<pre name="code" class="objc">#import <Foundation/Foundation.h> #import "User.h" @interface Status : NSObject @property (nonatomic, retain) NSString *text; @property (nonatomic, retain) NSString *icon;// 从1970-01-01 00:00:00 开始,一共度过了多少毫秒 @property (nonatomic, assign) long time;//@property (nonatomic) time_t time; @property (nonatomic, retain) User *user;//获取用户所有信息 @property (nonatomic, retain) Status *retweetStatus; @property (nonatomic, assign) int commentsCount; @property (nonatomic, assign) int retweetsCount; @end
#import "Status.h" @implementation Status - (void)dealloc{ [_text release]; [_user release]; [_retweetStatus release]; [_icon release]; [super dealloc]; } @end
#import <Foundation/Foundation.h> #import "User.h" #import "Status.h" int main(){// 新建2个用户 User *u = [[User alloc] init]; u.name = @"2B"; User *u2 = [[User alloc] init]; u2.name = @"傻B"; // 新建2条微博 Status *s = [[Status alloc] init]; s.text = @"今天天气真好!"; s.user = u; Status *s2 = [[Status alloc] init]; s2.text = @"今天天气真的很好!"; s2.retweetStatus = s; s2.user = u2; [u2 release]; [u release]; [s2 release]; [s release]; return 0; }8、循环引用@class
1.使用场景:对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类
2.格式:
@class + Card//@class仅仅是告诉编译器,Card是一个类
3.在实际开发中引用类的规范
1>.在.h文件中用@class来声明类
2>.在.m文件中用#import来包含类的所有东西
4.@class和#import的区别
1>.#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息
2>.如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方式就不会出现这种问题了,在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类
3>.两端循环引用(无法释放对象)解决方案:一端用retain,一端用assign
9、autorelease方法基本使用
1>.autorelease方法会返回对象本身,会将对象放到一个自动释放池,例:Person *p = [[[Person alloc] init] autorelease];调用autorelease方法后,对象计数器不变,不会-1,只有当自动释放池被销毁时,会对池子里面所有对象做一次release操作
int main(){ @autoreleasepool{//开始代表创建了释放池 Person *p = [[[Person alloc] init] autorelease]; }//结束代表销毁释放池 }注:@autoreleasepool{}可以无限使用,嵌套
2>.在实际开发中需要精确控制对象内存管理、对于占用内存较大的对象,不要随便用autorelease方法
3>.在IOS程序运行过程中,会创建无数个池子,这些池子都是以栈的结构存在,当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
说明:系统自带的方法里面没有包含alloc\new\copy,说明返回的对象都是autorelease的,在开发中经常会提供一个类方法,快速创建一个已经autorelease过的对象,创建对象时不要直接使用类名,一般用self,例:
+(id)person{ return[[[self alloc] init] autorelease]; }二、内存管理小结
1、计数器的基本操作
1> retain : +1
2> release :-1
3> retainCount : 获得计数器
2、set方法的内存管理
1> set方法的实现
- (void)setCar:(Car *)car{ if ( _car != car ){ [_car release]; _car = [car retain]; } }2> dealloc方法的实现(不要直接调用dealloc)
- (void)dealloc{ [_car release]; [super dealloc]; }3、@property参数
1> OC对象类型
@property (nonatomic, retain) 类名 *属性名;
@property (nonatomic, retain) Car *car;
@property (nonatomic, retain) id car;// 被retain过的属性,必须在dealloc方法中release属性
- (void)dealloc{ [_car release]; [super dealloc]; }2> 非OC对象类型(int\float\enum\struct)
@property (nonatomic, assign) 类型名称 属性名;
@property (nonatomic, assign) int age;
4、autorelease
1.系统自带的方法中,如果不包含alloc、new、copy,那么这些方法返回的对象都是已经autorelease过的[NSString stringWithFormat:....];[NSDate date];
2.开发中经常写一些类方法快速创建一个autorelease的对象* 创建对象的时候不要直接使用类名,用self