2009-07-25 45 views
13

這裏是我所指的代碼。增加對象的保留數量是什麼?

// Person.h 

@interface Person : NSObject { 
    NSString *firstName; 
    NSString *lastName; 
} 
@end 

// Person.m 

@implementation Person 
- (id)init { 
    if (![super init]) return nil; 
    firstName = @"John"; 
    lastName = @"Doe"; 
} 
@end 

// MyClass.m 

@implementation MyClass 
    ..... 
- (NSArray *)getPeople { 
    NSMutableArray *array = [[NSMutableArray alloc] init]; 

    int i; 
    for (i = 0; i < 10; i++) { 
     Person *p = [[Person alloc] init]; 
     [array addObject:p]; 
    } 

    return array; 
} 
    ..... 
@end 

現在,我知道在這個示例代碼中沒有進行內存管理。將需要什麼?

在getPeople循環中,我分配一個Person(retainCount 1),然後將其添加到數組中。保留計數現在是2,對不對?如果它是兩個,我應該在將它添加到數組後將[p釋放]添加到數組中,將retainCount降回到1?

我是對的,因爲調用者的責任是釋放該方法返回的數組? (這也會釋放人的記憶,以及它們的實例變量,假設它們的計數爲1)。

我已經閱讀了Apple的內存管理文檔,但是我猜我最不清楚的是增加一個對象的保留數量?儘管如此,我認爲我掌握了要釋放誰的責任。根據Apple的說法,這是基本規則:

如果您使用名稱以「alloc」或「new」開頭或包含「copy」的方法創建對象,則取得對象的所有權(例如alloc ,newObject或mutableCopy),或者如果您發送保留消息。您有責任放棄使用發行版或自動發行版所擁有的對象的所有權。任何其他時間你收到一個對象,你不能釋放它。

bobDevil的句子「只擔心你明確添加到項目中的保留數」讓它爲我點擊。在閱讀Apple的所有權政策後,本質上,創建新對象的對象/方法是負責釋放/關注它的人。它是否正確?

現在,讓我們說一個方法,它接收一個對象,並將它分配給一個實例變量。我需要保留正確的接收對象,因爲我仍然對它有興趣?

如果有任何不正確的地方,請告訴我。

回答

18

你是正確的,保留計數將它添加到一個陣列中後爲2。但是,您應該只關心顯式添加到項目中的保留計數。

保留一個對象是一個合同,說:「我沒有和你做完,不要離開。」一個基本的經驗法則(有例外,但通常記錄在案)是您在分配對象或創建副本時擁有對象。這意味着你給予的對象保留數爲1(不是自動發佈的)。在這兩種情況下,你應該在完成後釋放它。此外,如果您曾明確保留一個對象,則必須將其釋放。

所以,具體到你的例子,當你創建人,你有一個保留在它的計數。你把它添加到一個數組(它不管它,你不在乎),然後就大功告成了與人,所以你釋放它:

Person *p = [[Person alloc] init]; //retain 1, for you 
[array addObject:p]; //array deals with p however it wants 
[p release]; //you're done, so release it 

而且,正如我上面所說的,只有你一般在alloc或copy期間擁有對象,所以爲了與事物的另一端保持一致,您應該返回數組autoreleased,以便getPeople方法的調用方不擁有它。

return [array autorelease]; 

編輯: 正確的,如果你創建它,你必須將其釋放。如果你投資它(通過保留)你必須釋放它。

4

當您專門調用alloc時,保留計數會增加,因此您需要明確地釋放它。

工廠方法通常會給你一個自動釋放的對象(比如[NSMutableArray數組]) - 你必須特別保留這個以保持它的長度)。

至於NSArray和NSMutableArray addObject:,其他人將不得不評論。我相信你將一個類視爲一個黑盒子來處理他們自己的內存管理作爲設計模式,所以你永遠不會明確地發佈你已經傳入NSArray的東西。當它被破壞時,它應該處理遞減保留計數本身。

如果您將您的ivars聲明爲像@property(retain)suchAndSuchIvar這樣的屬性,並在您的實現中使用@synthesize,那麼您還可以獲得某種隱含的保留。 Synthesize基本上爲你創建了setter和getters,如果你明確地調用(保留),setter將保留傳入它的對象。它並非總是顯而易見的,因爲制定者可以構造這樣的:

Person fart = [[Person alloc] init]; 
fart.firstName = @"Josh"; // this is actually a setter, not accessing the ivar 
          // equivalent to [fart setFirstName: @"Josh"], such that 
          // retainCount++ 

編輯:

並儘可能的內存管理,只要你添加的對象數組,你用它做......所以:

for (i = 0; i < 10; i++) { 
     Person *p = [[Person alloc] init]; 
     [array addObject:p]; 
     [p release]; 
    } 

喬希

2

你通常應該/不/擔心保留計數。這是內部實施的。你應該只關心你是否想通過保留它來「擁有」一個對象。在上面的代碼中,數組應該擁有對象,而不是你(除了通過數組之外,你甚至沒有引用它的循環之外)。因爲您擁有[[Person alloc] init],您必須將其釋放。

因此

Person *p = [[Person alloc] init]; 
[array addObject:p]; 
[p release]; 

而且, 「getPeople」 的呼叫者應不擁有該陣列。這是公約。你應該先自動釋放它。

NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease]; 

你需要閱讀蘋果的內存管理文件:http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

+0

Josh說默認情況下NSMutableArray標記爲autorelease? – 2009-07-25 03:01:57