OC内存管理

一、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>.一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)

#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






















  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值