cobish.

导航

 

首先定义一个Student类和Book类,Student类里有Book类

Book.h

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface Book:NSObject {
 4     float _price;
 5 }
 6 
 7 @property float price;
 8 
 9 - (id)initWithPrice:(float)price;
10 
11 @end

Book.m  ("#pragma mark - 私有方法"注释方法分组 , "#pragma mark 构造方法" 注释方法)

 1 #import "Book.h"
 2 
 3 @implementation Book
 4 
 5 #pragma mark 构造方法
 6 - (id)initWithPrice:(float)price {
 7     if(self = [self init]) {
 8         _price = price;
 9     }
10     return self;
11 }
12 
13 #pragma mark 回收对象
14 - (void)dealloc {
15     NSLog(@"book's proce=%f 被销毁了", _price);
16     [super dealloc];
17 }
18 
19 @end

 Student.h

 1 #import <Foundation/Foundation.h>
 2 #import "Book.h"
 3 
 4 @interface Student:NSObject {
 5     int age;
 6     Book *_book;
 7 }
 8 
 9 @property int age;
10 
11 @property Book *book;
12 
13 - (id)initWithAge:(int)age;
14 
15 - (void)readBook;
16 
17 @end

Student.m

#import "Student.h"

@implementation Student

- (id)initWithAge:(int)age {
    if(self = [super init]) {
        _age = age;
    }
    return self;
}

- (void)dealloc {
    NSLog(@"student's age=%i 被销毁了", _age);
    [super dealloc];
}

- (void)readBook {
    NSLog(@"当前读的书的价格:%f", _book.price);
}

@end

main.m

 1 #import <Foundation/Foundation.h>
 2 #import "Book.h"
 3 #import "Student.h"
 4 
 5 int main(int argc, const char * argv[])
 6 {
 7     //这样没有内存泄漏
 8     @autoreleasepool {
 9            Student *stu = [[Student alloc] initWithAge:10]; //stu计数器为1
10 
11         Book *book =[[Book alloc] initWithPrice:3.5];//book计数器为1
12 
13         stu.book = book;  //book计数器为1
14 
15         [book release]; //book计数器为0
16 
17         [stu release]; //stu计数器为0
18     }
19     return 0;
20 }

 

上诉例子对象的内存没有泄露

但是,main方法写成下面的话,就会有危险

main.h

 1 #import <Foundation/Foundation.h>
 2 #import "Book.h"
 3 #import "Student.h"
 4 
 5 void test1(Student *stu) {
 6     Book *book = [[Book alloc] initWithPrice:3.5];  //book计数器为1
 7     
 8     stu.book = book; 
 9 
10     [book release];   //book计数器为0
11 }
12 
13 void test2(Student *stu) {
14     [stu readBook];
15 }
16 
17 int main(int argc, const char * argv[])
18 {
19     @autoreleasepool {
20            Student *stu = [[Student alloc] initWithAge:10];
21         
22         test1(stu);  //book计数器为1
23 
24         //这样做不安全,因为book已经在test被回收了
25         test2(stu);   //book计数器为0
26 
27         [stu release];
28     }
29     return 0;
30 }

 

 怎么解决呢? stu如果自己想使用book对象,那stu可以自己retain book,在回收时回收release book。

Student.m文件中修改

 1 //自己写setter方法
 2 - (void)setBook:(Book *)book {
 3     _book = [book retain];
 4 }
 5 
 6 //回收时回收release book
 7 - (void)dealloc {
 8     //释放Book对象
 9     [_book release];
10     
11     //或 [super.book release];
12 
13     NSLog(@"student's age=%i 被销毁了", _age);
14     [super dealloc];
15 }

 

当然上面的setter方法不太严谨,例如 main.h

 1 void test1(Student *stu) {
 2     Book *book = [[Book alloc] initWithPrice:3.5]; 
 3     
 4     stu.book = book; 
 5 
 6     [book release];  
 7 
 8     Book *book2 = [[Book alloc] initWithPrice:3.5]; 
 9     
10     stu.book = book2;  //这样的话book1计数器一直为1,内存泄露
11 
12     [book2 release]; 
13 }

解决方法是 在Student.m文件中修改setter方法

1 - (void)setBook:(Book *)book {
2     //先释放旧的成员变量
3     //[nil release]; 是不会报错的
4     [_book release];
5 
6     //再retain新的成员变量
7     _book = [book retain];
8 }

 

很不幸,上面的setter方法还是不严谨,例如 main.h

 1 void test1(Student *stu) {
 2     Book *book = [[Book alloc] initWithPrice:3.5]; 
 3     
 4     stu.book = book; 
 5 
 6     [book release];  
 7     
 8     //假如不小心多写了这行,会造成野指针
 9     stu.book = book;
10 
11     Book *book2 = [[Book alloc] initWithPrice:3.5]; 
12     
13     stu.book = book2; 
14 
15     [book2 release]; 
16 }

则可以写setter方法解决 Student.m

 

1 - (void)setBook:(Book *)book {
2     if(_book != book) {
3         //先释放旧的成员变量
4         [_book release];
5         //再retain新的成员变量
6         _book = [book retain];
7     }
8 }

 

这样就算是严谨的setter方法了。

 

 

 

 

 

 

 

 

 

posted on 2013-11-30 18:12  cobish.  阅读(95)  评论(0)    收藏  举报