首页 > 代码库 > Objective-C基础笔记(3)OC的内存管理

Objective-C基础笔记(3)OC的内存管理

Objective-C的内存基本管理

在OC中每个变量都保存着引用计数器,当这个对象的引用计数器为0的时候该对象会被回收。当使用alloc、new或者copy创建一个对象的时候,对象的引用计数器被置为1.

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

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

当OC被销毁的时候会发送一条dealloc消息(不要直接调用,由系统调用),可以重写dealloc方法,在该方法中释放相关资源。

可以给对象发送retainCount消息获取对象的当前引用计数器。

首先我们新建一个工程

接下来将工程的设置里面将ARC禁掉

Book.h文件

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

Book.m文件

  1. #import "Book.h"  
  2.   
  3. @implementation Book  
  4.   
  5. @synthesize price = _price;  
  6.   
  7. //构造函数  
  8. - (id)initBook:(float)price {  
  9.     if(self = [super init]){  
  10.         _price = price;  
  11.     }  
  12.     NSLog(@"价格是%f的书购买了", _price);  
  13.     return self;  
  14. }  
  15.   
  16. //析构函数  
  17. - (void)dealloc {  
  18.     NSLog(@"价格为%f的书被释放了", _price);  
  19.     [super dealloc];  
  20. }  
  21.   
  22. @end  

Student.h文件

  1. #import <Foundation/Foundation.h>  
  2. #import "Book.h"  
  3.   
  4. @interface Student : NSObject  
  5.   
  6. @property int age;  
  7. @property Book *book;  
  8.   
  9. - (void)setBook:(Book *)book;  
  10.   
  11. - (id)initStudent:(int)age;  
  12.   
  13. @end  

Student.m文件

  1. #import "Student.h"  
  2. #import "Book.h"  
  3.   
  4. @implementation Student  
  5.   
  6. @synthesize age = _age;  
  7. @synthesize book = _book;  
  8.   
  9. - (void)setBook:(Book *)book {  
  10.     if(_book != book){  
  11.         //先对原来的书计数器减一  
  12.         //如果之前为nil不会出错(和java中的空指针不同)  
  13.         [_book release];  
  14.         [book retain];  
  15.         _book = book;  
  16.     }  
  17. }  
  18.   
  19. //构造函数  
  20. - (id)initStudent:(int)age {  
  21.     if(self = [super init]) {  
  22.         _age = age;  
  23.     }  
  24.     NSLog(@"年龄为%d的学生被创建了", _age);  
  25.     return self;  
  26. }  
  27.   
  28. //析构函数  
  29. - (void)dealloc{  
  30.     [_book release];  
  31.     NSLog(@"年龄为%d的学生被释放了", _age);  
  32.     [super dealloc];  
  33. }  
  34.   
  35. @end  

main.m文件

  1. #import <Foundation/Foundation.h>  
  2. #import "Student.h"  
  3. #import "Book.h"  
  4.   
  5. void buyBook(Student *stu) {  
  6.     Book *book1 = [[Book alloc] initBook:101.5]; //谁创建谁释放  
  7.     stu.book = book1;  
  8.     [book1 release];  
  9.     Book *book2 = [[Book alloc] initBook:98.5];  
  10.     stu.book = book2;  
  11.     [book2 release];  
  12. }  
  13.   
  14. void readBook(Student *stu) {  
  15.     NSLog(@"年龄是%i的学生在读价格为%f的书", stu.age, stu.book.price);  
  16. }  
  17.   
  18. int main(int argc, const charchar * argv[]) {  
  19.     @autoreleasepool {  
  20.         //计数器为1  
  21.         Student *stu = [[Student alloc] initStudent:21];  
  22.         //买书  
  23.         buyBook(stu);  
  24.         //看书  
  25.         readBook(stu);  
  26.         //计数器清0,释放内存  
  27.         [stu release];  
  28.     }  
  29.     return 0;  
  30. }  

输出结果:

2014-11-13 23:11:19.510 内存管理[698:46519] 年龄为21的学生被创建了

2014-11-13 23:11:19.512 内存管理[698:46519] 价格是101.500000的书购买了

2014-11-13 23:11:19.512 内存管理[698:46519] 价格是98.500000的书购买了

2014-11-13 23:11:19.512 内存管理[698:46519] 价格为101.500000的书被释放了

2014-11-13 23:11:19.512 内存管理[698:46519] 年龄是21的学生在读价格为98.500000的书

2014-11-13 23:11:19.512 内存管理[698:46519] 价格为98.500000的书被释放了

2014-11-13 23:11:19.512 内存管理[698:46519] 年龄为21的学生被释放了

@class关键字

通常引用一个类有两种方法,一种是通过#import,另一种是通过@class.

#import 的方式会将头文件中的所有信息引入。

@class 的方式只是说明它是一个类(假如只是声明一个类就不用使用#import).

  1. #import <Foundation/Foundation.h>  
  2.   
  3. @class Book; //声明Book是一个类  
  4.   
  5. @interface Student : NSObject {  
  6.     Book *_book;  
  7. }  
  8.   
  9. @property int age;  
  10. @property Book *book;  
  11.   
  12. - (void)setBook:(Book *)book;  
  13.   
  14. - (id)initStudent:(int)age;  
  15.   
  16. @end  

另外,Student.m中的析构函数我们可以做如下修改

  1. //析构函数  
  2. - (void)dealloc{  
  3.     self.book = nil; //调用setter方法  
  4.     [_book release];  
  5.     NSLog(@"年龄为%d的学生被释放了", _age);  
  6.     [super dealloc];  
  7. }  

self.book = nil; 会调用setter方法,释放对象并将当前类Student的属性_book设为nil.

@property的参数

@property的参数格式: @property (参数1, 参数2,...) 类型 名字;

参数主要分为3类:

读写属性:readwrite / readonly

setter处理: assign / retain / copy

原子性:atomic / nonatomic

说明:

readonly代表只生成getter方法,默认是readwrite

assing默认(直接赋值),copy是setter方法release旧值,再copy新值

atomic(默认),保证getter和setter的原子性,提供多线程安全访问,nonatomic性能高,所以一般是选择nonatomic.

  1. #import <Foundation/Foundation.h>  
  2.   
  3. @class Book; //声明Book是一个类  
  4.   
  5. @interface Student : NSObject  
  6. //assign参数代表set方法直接赋值(默认的)  
  7. //getter方法是指定getter方法的名字  
  8. @property (nonatomic, assign, getter=getStudentAge) int age;  
  9. //这里的retain代表:release旧值,retain新值  
  10. //(注意,基本数据类型不能写retain参数)  
  11. @property (nonatomic, retain) Book *book;  
  12.   
  13. - (void)setBook:(Book *)book;  
  14.   
  15. - (id)initStudent:(int)age;  
  16.   
  17. @end  
  1. #import "Student.h"  
  2. #import "Book.h"  
  3.   
  4. @implementation Student  
  5.   
  6. //构造函数  
  7. - (id)initStudent:(int)age {  
  8.     if(self = [super init]) {  
  9.         _age = age;  
  10.     }  
  11.     NSLog(@"年龄为%d的学生被创建了", _age);  
  12.     return self;  
  13. }  
  14.   
  15. //析构函数  
  16. - (void)dealloc{  
  17.     self.book = nil; //调用setter方法  
  18.     [_book release];  
  19.     NSLog(@"年龄为%d的学生被释放了", _age);  
  20.     [super dealloc];  
  21. }  
  22.   
  23. @end  

自动释放池

自 动释放池是OC里面的一种内存自动回收机制,一般可以将一些临时变量添加到自动释放池中,统一回收释放。当自动释放池销毁时,池里的所有对象都会调用一次 release方法。OC对象只需要发送一条autorelease消息,就会把这个对象添加到最近的自动释放池中(栈顶的释放池)。

autorelease实际上只是把release的调用延迟了,对于每一次autorelease,系统只是把该对象放入当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会调用一次release方法。

  1. #import "Student.h"  
  2. #import "Book.h"  
  3.   
  4. @implementation Student  
  5.   
  6. //创建静态方法构造对象  
  7. + (id)student {  
  8.     Student *stu = [[[Student alloc] init] autorelease];  
  9.     return stu;  
  10. }  
  11.   
  12. //创建带参数的静态方法构造对象  
  13. + (id)studentWithAge:(int)age {  
  14.     Student *stu = [self student];  
  15.     stu.age = age;  
  16.     return stu;  
  17. }  
  18.   
  19. //构造函数  
  20. - (id)initStudent:(int)age {  
  21.     if(self = [super init]) {  
  22.         _age = age;  
  23.     }  
  24.     NSLog(@"年龄为%d的学生被创建了", _age);  
  25.     return self;  
  26. }  
  27.   
  28. //析构函数  
  29. - (void)dealloc{  
  30.     self.book = nil; //调用setter方法  
  31.     [_book release];  
  32.     NSLog(@"年龄为%d的学生被释放了", _age);  
  33.     [super dealloc];  
  34. }  
  35.   
  36. @end  
    1. int main(int argc, const charchar * argv[]) {  
    2.     //代表创建一个自动释放池  
    3.     @autoreleasepool {  
    4.         //第一种写法  
    5.         Student *stu = [[[Student alloc] initStudent:21] autorelease];  
    6.         Student *stu1 = [[[Student alloc] initStudent:21] autorelease];  
    7.   
    8.     } //当括号结束后,池子将被销毁  
    9.     //如果自动释放池被销毁,池里面的所有对象都会调用release方法  
    10.     @autoreleasepool {  
    11.         //第二种写法  
    12.         Student *stu2 = [[Student alloc] initStudent:21];  
    13.           
    14.         [stu2 autorelease];  
    15.     }  
    16.     @autoreleasepool {  
    17.         //第三种写法(推荐)  
    18.         //不用手动释放  
    19.         Student *stu3 = [Student student];  
    20.     }  
    21.     return 0;  

Objective-C基础笔记(3)OC的内存管理