在OC中每個變量都保存著引用計數器,當這個對象的引用計數器為0的時候該對象會被回收。當使用alloc、new或者copy創建一個對象的時候,對象的引用計數器被置為1.
給對象發送一條retain消息,可以使引用計數器+1.
給對象發送一條release消息,可以使引用計數器-1.
當OC被銷毀的時候會發送一條dealloc消息(不要直接調用,由系統調用),可以重寫dealloc方法,在該方法中釋放相關資源。
可以給對象發送retainCount消息獲取對象的當前引用計數器。
首先我們新建一個工程

接下來將工程的設置裡面將ARC禁掉

Book.h文件
#importBook.m文件@interface Book : NSObject @property float price; - (id)initBook:(float)price; @end
#import "Book.h"
@implementation Book
@synthesize price = _price;
//構造函數
- (id)initBook:(float)price {
if(self = [super init]){
_price = price;
}
NSLog(@"價格是%f的書購買了", _price);
return self;
}
//析構函數
- (void)dealloc {
NSLog(@"價格為%f的書被釋放了", _price);
[super dealloc];
}
@endStudent.h文件#importStudent.m文件#import "Book.h" @interface Student : NSObject @property int age; @property Book *book; - (void)setBook:(Book *)book; - (id)initStudent:(int)age; @end
#import "Student.h"
#import "Book.h"
@implementation Student
@synthesize age = _age;
@synthesize book = _book;
- (void)setBook:(Book *)book {
if(_book != book){
//先對原來的書計數器減一
//如果之前為nil不會出錯(和java中的空指針不同)
[_book release];
[book retain];
_book = book;
}
}
//構造函數
- (id)initStudent:(int)age {
if(self = [super init]) {
_age = age;
}
NSLog(@"年齡為%d的學生被創建了", _age);
return self;
}
//析構函數
- (void)dealloc{
[_book release];
NSLog(@"年齡為%d的學生被釋放了", _age);
[super dealloc];
}
@end
main.m文件#import輸出結果:#import "Student.h" #import "Book.h" void buyBook(Student *stu) { Book *book1 = [[Book alloc] initBook:101.5]; //誰創建誰釋放 stu.book = book1; [book1 release]; Book *book2 = [[Book alloc] initBook:98.5]; stu.book = book2; [book2 release]; } void readBook(Student *stu) { NSLog(@"年齡是%i的學生在讀價格為%f的書", stu.age, stu.book.price); } int main(int argc, const char * argv[]) { @autoreleasepool { //計數器為1 Student *stu = [[Student alloc] initStudent:21]; //買書 buyBook(stu); //看書 readBook(stu); //計數器清0,釋放內存 [stu release]; } return 0; }
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的學生被釋放了
#import 的方式會將頭文件中的所有信息引入。
@class 的方式只是說明它是一個類(假如只是聲明一個類就不用使用#import).
#import另外,Student.m中的析構函數我們可以做如下修改@class Book; //聲明Book是一個類 @interface Student : NSObject { Book *_book; } @property int age; @property Book *book; - (void)setBook:(Book *)book; - (id)initStudent:(int)age; @end
//析構函數
- (void)dealloc{
self.book = nil; //調用setter方法
[_book release];
NSLog(@"年齡為%d的學生被釋放了", _age);
[super dealloc];
}self.book = nil; 會調用setter方法,釋放對象並將當前類Student的屬性_book設為nil.參數主要分為3類:
讀寫屬性:readwrite / readonly
setter處理: assign / retain / copy
原子性:atomic / nonatomic
說明:
readonly代表只生成getter方法,默認是readwrite
assing默認(直接賦值),copy是setter方法release舊值,再copy新值
atomic(默認),保證getter和setter的原子性,提供多線程安全訪問,nonatomic性能高,所以一般是選擇nonatomic.
#import@class Book; //聲明Book是一個類 @interface Student : NSObject //assign參數代表set方法直接賦值(默認的) //getter方法是指定getter方法的名字 @property (nonatomic, assign, getter=getStudentAge) int age; //這裡的retain代表:release舊值,retain新值 //(注意,基本數據類型不能寫retain參數) @property (nonatomic, retain) Book *book; - (void)setBook:(Book *)book; - (id)initStudent:(int)age; @end
#import "Student.h"
#import "Book.h"
@implementation Student
//構造函數
- (id)initStudent:(int)age {
if(self = [super init]) {
_age = age;
}
NSLog(@"年齡為%d的學生被創建了", _age);
return self;
}
//析構函數
- (void)dealloc{
self.book = nil; //調用setter方法
[_book release];
NSLog(@"年齡為%d的學生被釋放了", _age);
[super dealloc];
}
@endautorelease實際上只是把release的調用延遲了,對於每一次autorelease,系統只是把該對象放入當前的autorelease pool中,當該pool被釋放時,該pool中的所有對象會調用一次release方法。
#import "Student.h"
#import "Book.h"
@implementation Student
//創建靜態方法構造對象
+ (id)student {
Student *stu = [[[Student alloc] init] autorelease];
return stu;
}
//創建帶參數的靜態方法構造對象
+ (id)studentWithAge:(int)age {
Student *stu = [self student];
stu.age = age;
return stu;
}
//構造函數
- (id)initStudent:(int)age {
if(self = [super init]) {
_age = age;
}
NSLog(@"年齡為%d的學生被創建了", _age);
return self;
}
//析構函數
- (void)dealloc{
self.book = nil; //調用setter方法
[_book release];
NSLog(@"年齡為%d的學生被釋放了", _age);
[super dealloc];
}
@endint main(int argc, const char * argv[]) {
//代表創建一個自動釋放池
@autoreleasepool {
//第一種寫法
Student *stu = [[[Student alloc] initStudent:21] autorelease];
Student *stu1 = [[[Student alloc] initStudent:21] autorelease];
} //當括號結束後,池子將被銷毀
//如果自動釋放池被銷毀,池裡面的所有對象都會調用release方法
@autoreleasepool {
//第二種寫法
Student *stu2 = [[Student alloc] initStudent:21];
[stu2 autorelease];
}
@autoreleasepool {
//第三種寫法(推薦)
//不用手動釋放
Student *stu3 = [Student student];
}
return 0;
}