首先定义一个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方法了。
浙公网安备 33010602011771号