内存管理

一、retain与release

每个对象内部都保存了一个与之相关联的整数,称为引用计数器

当使用allocnewcopy创建一个对象时,对象的引用计数器被设置为1

给对象发送一条retain消息,可以使引用计数器值+1

给对象发送一条release消息,可以使引用计数器值-1

给对象发送一条retainCount消息,可以获得当前的引用计数器值。

当一个对象的引用计数器值为0时,该对象将被销毁,其占用的内存将被回收,OC也会自动向对象发送一条dealloc消息,一般会重写dealloc方法释放相关资源,一定不要直接调用dealloc方法。

Student.m

 1 #import "Student.h"
 2 
 3 @implementation Student
 4 
 5 - (void)dealloc
 6 {
 7     NSLog(@"%@被销毁了", self);
 8     [super dealloc]; //一定要调用super的dealloc方法,且最好放在最后面调用
 9 }
10 
11 @end

main.m

 1 #import <Foundation/Foundation.h>
 2 #import "Student.h"
 3 
 4 int main(int argc, const char * argv[])
 5 {
 6 
 7     @autoreleasepool {
 8         
 9         Student *stu = [[Student alloc] init];
10         NSLog(@"stu.retainCount = %zi", stu.retainCount); //retainCount=1
11         
12         [stu retain];
13         NSLog(@"stu.retainCount = %zi", stu.retainCount); //retainCount=2
14         
15         [stu release];
16         NSLog(@"stu.retainCount = %zi", stu.retainCount); //retainCount=1
17         
18         [stu release]; //retainCount=0,对象销毁
19         
20         [stu release]; //EXC BAD ACCESS,会发生野指针错误,也就是说访问了不属于你的内存
21         
22     }
23     return 0;
24 }

控制台输出:

2013-04-27 23:17:40.958 Test3[1612:303] stu.retainCount = 1
2013-04-27 23:17:40.963 Test3[1612:303] stu.retainCount = 2
2013-04-27 23:17:40.965 Test3[1612:303] stu.retainCount = 1
2013-04-27 23:17:40.966 Test3[1612:303] <Student: 0x100109a10>被销毁了
2013-04-27 23:17:40.972 Test3[1612:303] <Student: 0x100109a10>被销毁了
Test3(1612,0x7fff79b12180) malloc: *** error for object 0x100109a10: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

二、对象之间的内存管理

Book.h

1 #import <Foundation/Foundation.h>
2 
3 @interface Book : NSObject
4 
5 @end

Book.m

 1 #import "Book.h"
 2 
 3 @implementation Book
 4 
 5 - (void)dealloc
 6 {
 7     NSLog(@"%@被销毁了", self);
 8     [super dealloc];
 9 }
10 
11 @end

Student.h

1 @class Book;
2 
3 @interface Student : NSObject {
4     Book *_book;
5 }
6 
7 @property Book *book;
8 
9 @end

Student.m

 1 #import "Student.h"
 2 #import "Book.h"
 3 
 4 @implementation Student
 5 
 6 - (Book *)book {
 7     return _book;
 8 }
 9 
10 - (void)setBook:(Book *)book {
11     if (_book != book) { //避免重复设置同一个Book导致book release后无法retain
12         [_book release]; //release旧值
13         _book = [book retain]; //retain新值
14     }
15 }
16 
17 - (void)dealloc
18 {
19     NSLog(@"%@被销毁了", self);
20     [_book release]; //释放book
21     [super dealloc];
22 }
23 
24 @end

main.m

 1 #import <Foundation/Foundation.h>
 2 #import "Student.h"
 3 #import "Book.h"
 4 
 5 int main(int argc, const char * argv[])
 6 {
 7 
 8     @autoreleasepool {
 9         
10         Book *book1 = [[Book alloc] init];
11         NSLog(@"book1.retainCount = %zi", book1.retainCount); //book1.retainCount=1
12         Book *book2 = [[Book alloc] init];
13         NSLog(@"book2.retainCount = %zi", book2.retainCount); //book2.retainCount=1
14         
15         Student *stu = [[Student alloc] init];
16         NSLog(@"stu.retainCount = %zi", stu.retainCount); //stu.retainCount=1
17         
18         stu.book = book1;
19         NSLog(@"book1.retainCount = %zi", book1.retainCount); //book1.retainCount=2
20         
21         stu.book = book1;
22         NSLog(@"book1.retainCount = %zi", book1.retainCount); //book1.retainCount=2
23         
24         stu.book = book2;
25         NSLog(@"book1.retainCount = %zi", book1.retainCount); //book1.retainCount=1
26         NSLog(@"book2.retainCount = %zi", book2.retainCount); //book2.retainCount=2
27         
28         [stu release]; //stu.retainCount=0,对象销毁
29         NSLog(@"book1.retainCount = %zi", book1.retainCount); //book1.retainCount=1
30         NSLog(@"book2.retainCount = %zi", book2.retainCount); //book2.retainCount=1
31         
32         [book1 release]; //book1.retainCount=0,对象销毁
33         [book2 release]; //book2.retainCount=0,对象销毁
34         
35     }
36     return 0;
37 }

控制台输出:

2013-04-28 01:03:35.229 Test3[1865:303] book1.retainCount = 1
2013-04-28 01:03:35.231 Test3[1865:303] book2.retainCount = 1
2013-04-28 01:03:35.233 Test3[1865:303] stu.retainCount = 1
2013-04-28 01:03:35.235 Test3[1865:303] book1.retainCount = 2
2013-04-28 01:03:35.236 Test3[1865:303] book1.retainCount = 2
2013-04-28 01:03:35.237 Test3[1865:303] book1.retainCount = 1
2013-04-28 01:03:35.238 Test3[1865:303] book2.retainCount = 2
2013-04-28 01:03:35.239 Test3[1865:303] <Student: 0x100109f70>被销毁了
2013-04-28 01:03:35.240 Test3[1865:303] book1.retainCount = 1
2013-04-28 01:03:35.241 Test3[1865:303] book2.retainCount = 1
2013-04-28 01:03:35.242 Test3[1865:303] <Book: 0x100109a40>被销毁了
2013-04-28 01:03:35.243 Test3[1865:303] <Book: 0x100102540>被销毁了

三、@property(retain)

每写一个setter方法都要写release和retain,可想而知非常麻烦,因此有了更简单的方法

Student.h

 1 @class Book
 2 
 3 @interface Student : NSObject
 4 
 5 //这里的retain代表:在setter方法中release旧值,retain新值
 6 @property(retain) Book *book;
 7 //在实现类中会自动生成以下代码
 8 //- (Book *)book {
 9 //    return _book;
10 //}
11 
12 //- (void)setBook:(Book *)book {
13 //    if (_book != book) {
14 //        [_book release];
15 //        _book = [book retain];
16 //    }
17 //}
18 
19 @end

Student.m

 1 #import "Student.h"
 2 #import "Book.h"
 3 
 4 @implementation Student
 5 
 6 
 7 - (void)dealloc
 8 {
 9     NSLog(@"%@被销毁了", self);
10     [_book release]; //释放book,这句代码不可省略
11     [super dealloc];
12 }
13 
14 @end

 

四、内存管理原则

1、谁创建,谁释放。如果通过allocnewcopy来创建一个对象,那么必须调用release或者autorelease

2、一般来说,除了allocnewcopy之外的方法创建的对象都被声明了autorelease

3、谁retain,谁release。只要调用了retain,无论这个对象是如何生成的,都要调用release

posted on 2013-04-27 22:14  蓝易  阅读(126)  评论(0编辑  收藏  举报