一.内存管理
对基本数据类型无效,只对任何继承了NSObject的对象有效
每个对象内部都保存有整数,这个整数称之为引用计数器
当一个对象的引用计数器值为0的话,它将被销毁,占用的内存被系统回收,
OC会自动向对象发送dealloc消息,一定不要直接调用dealloc方法。
一般会重写dealloc方法,在里面释放相关资源。
当使用 alloc new copy 创建一个对象时,对象的引用计数器为1,该对象会一直存在内存中,除非用户关闭应用。
给对象发消息,就是调用对象方法
给对象发送retain消息,引用计数器+1
给对象发送release消息,引用计数器-1
给对象发送retainCount可以获得当前对象的引用计数器值
内存管理法则
谁创建,谁释放
谁retain 谁release
在哪个方法里创建,就在哪个方法里释放
下面看一下内存管理的一段代码:
// Student.m
-
#import "Student.h"
-
-
@implementation Student
-
-
@synthesize age = _age;
-
-
-(void)dealloc{
-
-
NSLog(@"%@销毁了",self);
-
-
[super dealloc];//一定要调用super dealloc,最好放到最后面
-
}
-
-
@end
// main.m
-
#import <Foundation/Foundation.h>
-
#import "Student.h"
-
-
int main(int argc, const char * argv[]) {
-
@autoreleasepool {
-
-
Student *stu = [[Student alloc] init];
-
Student *stu1 = [[[Student alloc] init] autorelease];//在适当的时候,自动进行内存释放
-
-
NSLog(@"size--%zd",[stu retainCount]);
-
-
[stu retain];
-
-
NSLog(@"size--%zd",[stu retainCount]);
-
-
[stu release];
-
-
NSLog(@"size--%zd",[stu retainCount]);
-
-
[stu release];
-
-
//[stu release];//会导致野指针错误,内存已经被释放,指针还去访问他。
-
-
}
-
return 0;
-
-
}
运行结果:
2015-04-09 15:26:41.312 内存管理-1[9838:303] size--1
2015-04-09 15:26:41.314 内存管理-1[9838:303] size--2
2015-04-09 15:26:41.314 内存管理-1[9838:303] size--1
2015-04-09 15:26:41.315 内存管理-1[9838:303] 销毁了
2015-04-09 15:26:41.315 内存管理-1[9838:303] 销毁了
二.对象之间的内存管理
看下面的代码,会导致野指针错误:
// Student.m
-
#import "Student.h"
-
-
@implementation Student
-
-
//@synthesize age = _age;
-
-
-(void)dealloc{
-
-
NSLog(@"age--%d--销毁了",_age);
-
-
[super dealloc];
-
}
-
-
-(id)initWithAge:(int)age{
-
-
if((self = [super init]) != nil){
-
-
_age = age;
-
-
}
-
return self;
-
-
}
-
-
-(void)readBook{
-
-
-
NSLog(@"读的书是:%f",_book.price);
-
-
}
-
-
@end
// main.m
-
#import <Foundation/Foundation.h>
-
#import "Student.h"
-
#import "Book.h"
-
-
-
void test(Student *stu){
-
-
-
Book *bo = [[Book alloc] initWithBook:9.9];
-
-
stu.book = bo;
-
-
[bo release];
-
-
}
-
-
void test1(Student *stu){
-
-
[stu readBook];//会引起野指针
-
-
}
-
-
int main(int argc, const char * argv[]) {
-
@autoreleasepool {
-
-
Student *stu = [[Student alloc] initWithAge:39];
-
-
//Book *bo = [[Book alloc] initWithBook:3.2];
-
-
test(stu);
-
test1(stu);
-
-
[stu release];
-
//[bo release];
-
-
}
-
return 0;
-
-
}
谁想使用对象,谁就retain
针对上述代码的改进,看下下面的代码:
// Student.m
-
#import "Student.h"
-
-
@implementation Student
-
-
//@synthesize age = _age;
-
-
-(void)dealloc{
-
-
NSLog(@"age--%d--销毁了",_age);
-
-
[_book dealloc];//释放student时候释放book
-
-
[super dealloc];
-
}
-
-
-(id)initWithAge:(int)age{
-
-
if((self = [super init]) != nil){
-
-
_age = age;
-
-
}
-
return self;
-
-
}
-
-
-(void)readBook{
-
-
-
NSLog(@"读的书是:%f",_book.price);
-
-
}
-
-
-(void)setBook:(Book *)book{
-
-
_book = [book retain];//使用了就retain
-
-
}
-
-
-(Book *)book{
-
-
return _book;
-
}
-
-
-
@end
修改以下函数后,还是会出现内存泄露,如下:
因为set了两遍,所以retain了两遍,但是释放时候只release了一遍
-
void test(Student *stu){
-
-
Book *bo = [[Book alloc] initWithBook:9.9];
-
-
stu.book = bo;
-
-
[bo release];
-
-
Book *bo1 = [[Book alloc] initWithBook:9.9];
-
-
stu.book = bo1;
-
-
[bo1 release];
-
-
-
}
OC里面给一个空的对象发送消息是不会错的
//防止上述内存泄露,可以这样写
-(void)setBook:(Book *)book{
//先释放就的成员变量,虽然有可能是nil
[_book release];
_book = [book retain];
}
-
void test(Student *stu){
-
-
Book *bo = [[Book alloc] initWithBook:19.9];
-
stu.book = bo;
-
-
[bo release];
-
-
stu.book = bo;//这里会引起野指针,因为重复调用了set方法
-
-
Book *bo1 = [[Book alloc] initWithBook:9.9];
-
-
stu.book = bo1;
-
-
[bo1 release];
-
-
-
}
[_book release];
[_book release];//这样是野指针,是不可以的
[nil release];//这样不是野指针,属于空指针,是可以的。
写成这样会避免上诉情况
-(void)setBook:(Book *)book{
if(book != _book){
//先释放就的成员变量
[_book release];
_book = [book retain];
}
}
EXC_BAD_ACCESS 野指针错误
阅读(519) | 评论(0) | 转发(0) |