跟Java和C#相似,OC建立的對象在堆上。與Java和C#不一樣的是Java和C#有垃圾回收機制,因此不須要程序員手動釋放堆上的內存。而OC沒有垃圾回收機制,必須手動管理內存的建立和釋放。下面介紹一下OC內存管理內存管理的方式。程序員
OC管理內存的方式相似C++中的智能指針,建立一個對象時,在ObjC中每一個對象內部都有一個與之對應的整數(retainCount),叫「引用計數器」,當一個對象在建立以後初始化它的引用計數器爲1,當調用這個對象的alloc、retain、new、copy方法以後引用計數器自動在原來的基礎上加1(ObjC中調用一個對象的方法就是給這個對象發送一個消息),當調用這個對象的release方法以後它的引用計數器減1,若是一個對象的引用計數器爲0,則系統會自動調用這個對象的dealloc方法來銷燬這個對象。this
Student.h文件:atom
1 #import <Foundation/Foundation.h> 2 3 @interface Student : NSObject 4 5 #pragma mark - 屬性 6 @property (nonatomic,copy)NSString *name; 7 @property (nonatomic,assign)float age; 8 9 @end
Student.m文件:spa
1 #import "Student.h" 2 3 @implementation Student 4 5 -(void)dealloc{ 6 NSLog(@"Invoke Student dealloc method"); 7 [super dealloc]; 8 } 9 @end
main.m文件:指針
1 #import <Foundation/Foundation.h> 2 #import "Student.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 8 // insert code here... 9 Student *stu = [[Student alloc]init]; 10 stu.name=@"lisi"; 11 stu.age=12; 12 NSLog(@"retainCount=%lu",[stu retainCount]); 13 //結果爲1 14 [stu retain]; 15 NSLog(@"retainCount=%lu",[stu retainCount]); 16 //結果爲2 17 [stu release]; 18 NSLog(@"retainCount=%lu",[stu retainCount]); 19 //結果爲1 20 [stu release]; 21 stu=nil; 22 [stu release]; 23 } 24 return 0; 25 }
咱們能夠看出,在建立一個對象以後,初始化引用計數器爲1,retain以後,計數器增長1,而後每release一次,計數器都會減1,直到這個對象被釋放。code
對象之間引用能夠是複雜的,有時候會出現相互引用既循環引用的狀況,因此對象的釋放不能牢牢依靠自動化來完成。內存釋放的原則是誰建立,誰釋放。以下:對象
Book.h:blog
1 #import <Foundation/Foundation.h> 2 3 @interface Book : NSObject 4 @property (nonatomic,copy) NSString *bookName; 5 -(void)read; 6 -(id)initWithName:(NSString*) bname; 7 @end
Book.m內存
1 #import "Book.h" 2 3 @implementation Book 4 -(void)read{ 5 NSLog(@"now read this book %@...",self.bookName); 6 } 7 -(id)initWithName:(NSString*) bname{ 8 [super init]; 9 _bookName=bname; 10 return self; 11 } 12 -(void)dealloc{ 13 NSLog(@"Invoke book %@ dealloc method...",self.bookName); 14 [super dealloc]; 15 } 16 @end
Student.h資源
1 #import <Foundation/Foundation.h> 2 #import "Book.h" 3 @interface Student : NSObject{ 4 Book *_book; 5 } 6 7 #pragma mark - 屬性 8 @property (nonatomic,copy)NSString *name; 9 @property (nonatomic,assign)float age; 10 -(id)initWithNameAndAge:(NSString*)sname andAge:(float) sage; 11 -(void)setBook:(Book*)book; 12 -(Book*)book; 13 @end
Student.m
1 #import "Student.h" 2 3 @implementation Student 4 5 -(id)initWithNameAndAge:(NSString *)sname andAge:(float)sage{ 6 self.name=sname; 7 self.age=sage; 8 return self; 9 } 10 -(void)setBook:(Book *)book{ 11 if (_book!=book) { 12 [_book release]; 13 _book = [book retain]; 14 } 15 } 16 17 -(Book*)book{ 18 return _book; 19 } 20 21 -(void)dealloc{ 22 NSLog(@"Invoke Student dealloc method"); 23 [_book release]; 24 [super dealloc]; 25 } 26 @end
main.m
1 #import <Foundation/Foundation.h> 2 #import "Student.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 8 // insert code here... 9 Student *stu = [[Student alloc]initWithNameAndAge:@"sili" andAge:12]; 10 11 Book *book1 = [[Book alloc]initWithName:@"AAA"]; 12 [book1 release]; 13 [stu.book read]; 14 15 Book *book2 = [[Book alloc]initWithName:@"BBB"]; 16 [stu setBook:book2]; 17 [book2 release]; 18 [stu.book read]; 19 [stu release]; 20 } 21 return 0; 22 }
運行結果:
1 2015-05-03 11:59:24.939 first[1814:303] Invoke book AAA dealloc method... 2 2015-05-03 11:59:24.941 first[1814:303] now read this book BBB... 3 2015-05-03 11:59:24.942 first[1814:303] Invoke Student dealloc method 4 2015-05-03 11:59:24.942 first[1814:303] Invoke book BBB dealloc method...
其實咱們能夠直接利用OC提供的屬性來達到一樣的效果:
@property (nonatomic,retain)Book *book;
屬性包含的全部參數和用法以下:
若是不進行設置或者只設置其中一類參數,程序會使用三類中的各個默認參數,默認參數:(atomic,readwrite,assign)。通常狀況下若是是基本類型使用assign,非字符串對象使用retain,字符串對象使用copy。原子性和讀寫屬性根據須要設置便可。
自動內存釋放使用@autoreleasepool關鍵字聲明一個代碼塊,若是一個對象在初始化時調用了autorelase方法,那麼當代碼塊執行完以後,在塊中調用過autorelease方法的對象都會自動調用一次release方法。
1 #import <Foundation/Foundation.h> 2 #import "Student.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 8 // insert code here... 9 Student *stu = [[Student alloc]initWithNameAndAge:@"lisi" andAge:12]; 10 Student *stu1 = [[[Student alloc]initWithNameAndAge:@"wanger" andAge:14]autorelease]; 11 [stu1 retain]; 12 [stu autorelease]; 13 } 14 return 0; 15 }
打印結果:
1 2015-05-03 12:27:39.949 first[1938:303] Invoke Student dealloc lisi method
咱們能夠看出,stu對象被徹底釋放,而stu1沒有被釋放,這是由於每一個對象的release方法只被調用了一次,而stu1的引用計數爲2,因此在代碼塊結束的時候stu1對象不會被釋放(形成了內存泄露)。對於自動內存釋放有如下幾點須要注意: