在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]; } @endmain.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]; } @end
autorelease實際上只是把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]; } @end
int 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; }