Object Ownership Policy
每一個物件(object)會有一個或多個的擁有者(owner)。只要物件有擁有者(owner),這個物件就不會消失;若物件沒有擁有者,系統會自行銷毀(destroy)這個物件。創建即擁有 |
當你使用alloc, new, copy, mutableCopy時,就代表你創建(create)一個物件(object),也就擁有物件(object)的擁有權 |
使用retain就能獲得物件的擁有權 |
一個物件可以擁有一個以上的擁有者。如果你希望一個物件繼續存在,可以使用retain獲得擁有權,讓物件繼續存在。 |
使用結束須放棄擁有權 |
可以送出"release"或"autorelease"訊息來放棄擁有權 |
不能放棄非自身擁有的物件 |
Retain Counts
每個物件都可以呼叫"retain count"來計算目前的擁有者數量當你創建一個物件時,物件的retain count為1
當傳送retain 給物件,retain count會增加1
當傳送release給物件,retain count會減1
當傳送autorelease給物件,代表未來retain count將會減少1
當物件的retain count減少至0的時候,物件就會被dealloc
Autorelease
Autorelease是在NSObject中定義的。送出autorelease訊息,代表你在未來會放棄對物件的擁有權。可以採用下面這個例子來實做:
– (NSArray *)sprockets
{
NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,auxiliarySprocket, nil];
return [array autorelease];
}
在這個例子中使用了alloc,因此我們擁有了array的擁有權,並且有「放棄擁有權」的責任。這時候我們就可以使用autorelease。
也可以以下面的方式來實做這個function:
– (NSArray *)sprockets
{
NSArray *array = [NSArray arrayWithObjects:mainSprocket,auxiliarySprocket, nil];
return array;
}
這個例子中,我們並沒有得到array的擁有權,因此我們不需要放棄擁有權。
Validity of Shared Objects
接收的物件可以在整個function的scope中使用,也可以在此function中回傳這個接受到的物件,且不需擔心物件被release掉。以下有兩個例外的例子:
1. 把物件從collection中移除
heisenObject = [array objectAtIndex:n];
[array removeObjectAtIndex:n];
// heisenObject could now be invalid.
當一個物件從collection移除的時候,會送出一個release訊息。如果這個collection是物件唯一的擁有者,物件就會被dealloc2. 當"parent object" 被dealloc
id parent = <#create a parent object#>;
... //
heisenObject = [parent child] ;
[parent release]; // Or, for example: self.parent = nil;
// heisenObject could now be invalid.
當我們release外層的物件,且外層物件是內層物件的唯一擁有者,那內層物件會和外層物件一起被deallocAccessor Methods
如果你的class中有一個物件變數,你必須確定他不會在你使用的時候被release掉。當物件被設定的時候,你必須得到這個物件的擁有權,也必須在使用完後放棄擁有權。
Deallocating an Object
當retain count為0的時候,物件就會被dealloc,dealloc method會自動的被呼叫。Dealloc method的目的是把object所擁有的記憶體釋放掉。
如果你的class裡面有實例變數,你就必須實做dealloc 方法將這些實例變數release掉,並呼叫父類別的dealloc。
舉例來說,如果我們有兩個實例變數: mainSprocket 和 auxiliarySprocket 。就必須像下面這樣,實做dealloc。
- (void)dealloc {
[mainSprocket release];
[auxiliarySprocket release];
[super dealloc];
}
Objects Returned by Reference
有些在Coca定義的object會以位址傳回。有些method會使用NSError來包含錯誤資訊,像是:
● initWithContentsOfURL:options:error: (NSData)
● initWithContentsOfFile:encoding:error: (NSString)
● executeFetchRequest:error: (NSManagedObjectContext)
如果我們呼叫這些方法,我們並沒有創建NSError物件,所以我們並沒有擁有權,也不需要去release他。
NSString *fileName = <#Get a file name#>;
NSError *error = nil;
NSString *string = [[NSString alloc] initWithContentsOfFile:fileName
encoding:NSUTF8StringEncoding error:&error];
if (string == nil) {
// deal with error ...
{
... //
[string release];
Retain Cycles
在某些情況下,兩個object有可能會有循環參照的情形。
舉例來說,考慮一個文字程式的物件關係:
一個Documet object會創建document中的每一頁(Page Object),每一個Page object會有一個實例變數來儲存Page Object是屬於哪一個document object。若Document object retain 了Page object而且Page object也retain 了Document object,到page object release之前 Document object的retain count 不會為0,且Page object也不會被release掉,除非Document被dealloc。
解決方法是,父親物件retain子物件,但是子物件不retain父親物件。Weak References to Objects
當我們retain一個object時,會產生"強"參考。一個物件擁有強參考是不會被release掉的,強參考決定了一個object的壽命。在某些情況下,你可能不希望物件不自動dealloc,這時候可以使用"弱"參考。使用pointer來儲存物件產生弱參考。
弱參考可以應用循環參照上。舉例來說,object A和B互相溝通,A和B都需要一個對方的參照,如果A和B互相都retain對方,那麼A和B都不會被dealloc。要打破這種循環參照的方式,其中的一個object必須是另一個object的子object並以弱參考連結另一個object。
以實際的例子來說,在一個階層式的view中, 一個parent view擁有他的child view,但child view並不擁有他的parent,而child view仍然需要知道他的parent view是誰,因此在child內保留一個弱參考到他的parent。
假設有一個物件,你只擁有了一個弱參考指向這個物件,傳送訊息給物件的時候就必須注意。如果你傳送了一個訊息給已經dealloc的物件,應用程式就會crash。你必須明確的定義物件什麼時候有效。
沒有留言:
張貼留言