2012-09-02 65 views
1

例如: 我們總是這樣寫的方法1:爲什麼被調用者返回自動釋放對象而不是返回保留對象並讓調用者釋放對象?

-(NSObject*)giveMeAnObject 
{ 
    return [[[NSObject alloc] init] autorelease]; 
} 

-(void)useObject 
{ 
    NSObject *object = [self giveMeAnObject]; 
    //use that object 
} 

,但我們爲什麼不寫這樣的方式2:

-(NSObject*)giveMeAnObject 
{ 
    return [[NSObject alloc] init]; 
} 

-(void)useObject 
{ 
    NSObject *object = [self giveMeAnObject]; 
    //use that object 
    [object release]; 
} 

可可SDK做這樣的事情的方式1,我這就是爲什麼我們都使用方式1,它已經成爲一種編碼習慣。 但我只是認爲,如果約定是方式2,我們可以獲得很少的性能改進。

那麼除編程約定外,還有其他什麼原因使用方式1代替方式2嗎?

+0

總是有機會忘記釋放它。在代碼中將分配和釋放分離太遠是潛在的錯誤來源。特別是當你在一個函數中分配一些東西作爲返回對象時。 – nhahtdh

+0

這是一個所有權問題。在情況1中,自動釋放的對象由方法返回,因爲它可能屬於類或框架,而不是調用者。 – CodaFi

回答

4

返回一個自動釋放對象是一種抽象的形式 - 開發人員的方便,所以他/她不必考慮返回對象的引用計數 - 因此會導致更少的特定錯誤類別(儘管您也可以說autorelease池引入了新的類別的錯誤或複雜性)。它可以真正簡化客戶端代碼,但是,可能會有性能問題。當不需要進行參考操作時,它也可以用作抽象優化 - 考慮對象何時持有返回的實例並且不需要進行保留或複製。儘管鏈接語句可以被過度使用,但這種做法對於鏈接語句也很方便。

此外,確定引用計數錯誤的靜態分析器對於這些庫和程序中的一些來說是相對較新的。 Autorelease池在ARC之前,對objc對象的引用計數進行多年的靜態分析 - 確保您的引用計數正確,現在使用這些工具更簡單。他們能夠檢測到許多錯誤。

當然,如果您喜歡簡單的返回自動釋放對象 - 使用ARC,您可以返回更少的自動釋放對象,而無需引入抽象的autorelease池錯誤。

使用統一的所有權語義也簡化了程序。如果抽象選擇器或選擇器集合總是使用相同的語義返回,那麼它確實可以簡化一些通用形式。例如 - 如果傳遞給performSelector:的一組選擇器具有不同的所有權返回語義,則會增加很多複雜性。如此統一的所有權歸還可以真正簡化一些更「通用」的實現。

性能:引用計數操作(保留/釋放)可能相當重要 - 尤其是如果您習慣於在較低級別工作。但是,當前的自動釋放池實現速度非常快。它們最近被更新了,並且比以前更快。編譯器和運行庫使用幾個特殊的快捷鍵來降低這些成本。保持autorelease池的大小也是一個好主意 - 特別是在移動設備上。創建一個autorelease池非常快。實際上,您可能會從自動釋放操作本身增加零個百分點到幾個百分點(即消耗的時間比objc_msgSend +變體少得多)。有些測試甚至跑得快一點。這不是許多人將從中獲得的優化。在典型情況下,它不會成爲低掛果實,而且在真實計劃中衡量這種變化的效果和地點實際上相對困難 - 基於我在bbum提到下面的變化之後所做的一些測試。所以測試範圍有限,但MRC和ARC似乎更好/更快。

因此,如果您正在執行自己的引用計數操作,很多情況都歸結於您想要承擔的責任級別。對於大多數人來說,它不應該改變他們的寫作方式。我認爲本地化內存問題,更多確定性的對象破壞,以及更可預測的堆大小是人們可能喜歡的主要原因如果您在現代系統上運行,則返回「擁有」(+1)引用計數。即使如此,在很多情況下,運行時和編譯器都會爲您減少這個數量(請參閱bbum的答案+1)。儘管自動釋放池大約一樣快,但我現在不打算比現在更多地使用它們 - 所以仍然有合理的理由儘量減少使用它們,但原因正在減少。

+1

+1 ...我會磨練*重大*索賠。他們*可能會產生重大影響,但這通常表明架構中存在其他問題。在近期發佈的版本中,autorelease的成本大大降低。 – bbum

+0

@bbum ahoy - 謝謝你指出。花了一些時間與分析器並相應地更新了答案。乾杯。 – justin

3

您是否衡量了性能優勢?你有一個可量化的情況,其中autorelease與CF風格的調用者必須釋放有可衡量的性能影響?

如果不是,則模擬點。如果是這樣,我敢打賭,有一個系統性的架構問題,遠遠超越autorelease而不是。

無論如何,如果你採用ARC,autorelease的「成本」是最小化。編譯器和運行庫實際上可以跨方法調用優化autorelease。

0

主要有三個方面的原因:

  1. 它規定的取得所有權的概念。
  2. 它消除了懸掛指針的問題。
  3. 它返回在本地自動發佈池中創建的對象,從而提高性能。