Object C 內存管理
一. 基本概念:
1. iPhone系統中的Objective-C的內存管理機制是比較靈活的,即可以拿來像C/C++一樣用,也可以加個AutoreleasePool讓它升級為半自動化的內存管理語言;
2. 引用計數是實例對象的內存回收唯一參考
引用計數(retainCount)是Objective-C管理對象引用的唯一依據。調用實例的release方法後,此屬性減一,減到為零時對象的dealloc方法被自動調用,進行內存回收操作,也就是說我們永不該手動調用對象的dealloc方法.
3. “擁有的概念”
1) 擁有一個對象的使用權,我們稱為擁有這個對象;對象的擁有者個數至少為1,對象才得以存在,否則它應該立即銷毀;
2) 獲得一個對象所有權的方法:當對對象做alloc,copy,和retain操作之後;
4. “引用”d的概念
面向對象領域裡有個引用的概念,區別於繼承,引用常被用來當做偶合性更小的設計。一個實例擁有另一個實例的時候,我們稱它為引用了另一個實例。
比如ClassA類的一個屬性對象的Setter方法:
- ( void )setMyArray:(NSMutableArray *)newArray {
if (myArray != newArray) {
[ myArray setMyArray:nil ];// 這裡不用release思考為什麼,(在實例的dealloc方法中會調用myArray的realse方法)
myArray = [newArray retain];
}
}
5. 引用記數:
每個對象都有一個引用記數(retainCount),對象被創建的時候引用記數為1;
6. 2
二. 內存管理API及使用准則:
1. alloc:為一個新對象分配內存,並且它的引用記數為1;調用alloc方法,你便擁有新對象的所有權;
2. copy:制造一個對象的副本,改副本的retainCount為1,調用者擁有對副本的所有權;
3. retain: 使retainCount+1;並且擁有對象所有權;
4. release:使retainCount-1;
5. autorealse: 未來的某個時刻使retainCount-1;
6. dealloc:不要手動調用,而是在系統retainCount為0時自動調用;
- (void)dealloc{
[name release];
[super dealloc];
}變量的release順序與初始順序相反;
三. 內存管理的原則:
以 1 2 3為A類,(retainCount+1);
以 4,5為B類:retainCount-1
1 .對於同一個對象所做的,A與B的調用次數保持一致;
2. 凡是通過alloc,retain,copy等手段獲得對象的所有權;必須在不適用的 使用自己調用release或autoRelease釋放;
3. 不要釋放不屬於自己的對象;
4. autorelease只是意味著延遲發送一個release消息;
5. 對於便利構造器和訪問器來說,不用進行釋放,因為沒有獲得對象的使用權;
四. 使用小例子:
1.
Person *person1 = [[Person alloc] initWithName:@”張三”];
NSLog(@”name is %@”,person1.name); //假設從這往後,我們一直都不使用person1 了,應該把對象給釋放了。
[person1 release];
2.
erson *person2 = [Person alloc]initWithName:@”李四”];
NSString *name = person2.name;NSLog(@”%@”,name); //假設從這以後,我們也不使用person2了。
[person2 release];
//不應該釋放name,因為name是我們間接獲得的,所以沒有它的所有權
3. 由便利構造器產生的對象不應當使用者銷毀,而是由便利構造器本身完成。
+(id) personWithName:(NSString *)aName
{
Person *person = [[Person alloc]
initWithName:aName];
return person; }
①錯誤,因為返回person對象後,類失去了釋放這個對象的機會;
②如果在return語句前加上:[person release];也錯誤,因為對象已經銷毀,不能使用;
③:正確做法:return語句前加上:[person autorelease];
(二)使用便利構造器創建的對象,不需要進行釋放;
如:
-(void) printHello
{
NSString *str = [NSString
stringWithFormat:@”Hello”];
NSLog(@”%@”,str); }
4. 訪問器和設置器:
1)在設置器中,保持對新傳入對象的所有權,同時放棄舊對象的所有權。
-(void) setName:(NSString *) aName{ if(name!= aName){
[name release];//有疑問,會不會造成多次釋放;
name = [aName retain];//or copy }
}
2) 在訪問器中,不需要retain或release.
-(NSString *)name{
return name; }
3) 用訪問器獲得的對象,使用完畢後不需要釋放。
-(void) printName{
NSString *name = person.name;
NSLog(@”%@”,name); }
5. 常見錯誤:
1) 未使用設置器
-(void) reset{
NSString *newName = [[NSString alloc]
initWithFormat:@”theNew”]; name = newName;
[newName release]; }
2)內存洩露
-(void) reset{
NSString *newName = [[NSString alloc]
initWithFormat:@”theNew”];
[self setName:newName];
}
3) 釋放沒有所有權的對象
-(void) reset{
NSString *newName = [NSString
stringWithFormat:@”theNew”];
[self setName:newName];
[newName release];
}