2011-03-08 67 views
10

我一直在審查蘋果文檔和示例代碼,嘗試確定管理IBOutlets內存的最佳方式。至少可以說,我有點困惑。iOS - 管理IBOutlets內存的最佳方法是什麼?

的CurrentAddress樣本代碼聲明IBOutlets作爲屬性:

@interface MapViewController : UIViewController <MKMapViewDelegate, MKReverseGeocoderDelegate> 

{ 
    MKMapView *mapView; 
    UIBarButtonItem *getAddressButton; 
} 
@property (nonatomic, retain) IBOutlet MKMapView *mapView; 
@property (nonatomic, retain) IBOutlet UIBarButtonItem *getAddressButton; 

大。這些被釋放dealloc:

- (void)dealloc 
{ 
    [mapView release]; 
    [getAddressButton release]; 
    [super dealloc]; 
} 

現在不應該將這些屬性設置爲分配?因爲當設置爲保留時,IBOutlet的保留計數將增加兩次:一次是裝入筆尖時,另一次是屬性設置時間?將這些屬性設置爲零而不是釋放dealloc會不會更好?

回答

7

蘋果文檔說我們應該保留iOS的屬性。
應該釋放留存網點,並在deallocviewDidUnload這兩個網址中發佈nil

在Mac上,加載筆尖時,未被超級視圖保留的每個插座都會自動保留。 iOS的情況並非如此。這就是爲什麼在視圖層次結構中只保留視圖以外的視圖在理論上是有效的。

Jeff LaMarche對此主題有一個非常有幫助的帖子:Outlets, Cocoa vs. Cocoa Touch

+0

@Jilouc:你爲什麼不在你的dealloc方法中釋放它們後立即將IBOutlet設置爲null?不把這些調用分成兩種方法會讓你面對潛在的問題? – FreeAsInBeer 2011-03-08 13:38:21

+0

,因爲你可能不是釋放它的人(它可能是在@synthesize裏面釋放),並且viewDidUnload比dealloc更快發生,這會更快地釋放內存 – slf 2011-03-08 13:43:32

+0

我不夠精確(回答編輯)。我也在dealloc中設置了零售店。一般來說,我在viewDidUnload中使用'self.myOutlet = nil'(用於釋放+ nil)和'[myOutlet release],myOutlet = nil;'在'dealloc'中。但這只是一種習慣。 – Jilouc 2011-03-08 13:45:43

2

一旦nib加載器完成加載所有內容並連接所有IBOutlet,它就會自動釋放它加載的所有對象。如果您的IBOutlet屬性被聲明爲assign,那麼在下次autorelease池清空時,它指向的對象將被刪除。

您可以將屬性設置爲dealloc而不是直接釋放它們,結果是相同的。需要注意的是,如果您提供了自己的setter實現,則需要記住對象的某些其他成員可能已經被釋放。

1

這對MacOSX和iOS來說是不同的。在iOS中,加載視圖並建立筆尖連接後,保留計數將爲2。

這些元素中的每一個都將被視圖保留一次,並由您的控制器保留一次。視圖中的其他元素將僅保留僅視圖。

當您的控制器釋放這兩個元素時,它們的保留數減少到一個。之後,[super dealloc]被調用。 UIViewController在其dealloc中有一個[view release],所以視圖被釋放(除非保留在別處或以前發佈)。當視圖被釋放時,它釋放它的子視圖,並且元素最終被完全釋放。

在dealloc中,[對象發佈]是首選的原因是當您編寫[self setObject:nil]時,鍵值編碼(或您自己的代碼)可能會導致運行其他代碼。這可能會導致其他對象在您的控制器處於釋放中間時與其進行交互。出於同樣的原因,不應該在init方法中使用Setter。

剛剛發佈版本還有第二個原因。通過保留該值並且不將它設置爲零,我們會注意到代碼是否在dealloc期間錯誤地訪問了該對象上的變量。這可以幫助捕獲可能不容易追蹤的錯誤。

0

我假設你@synthesize這些屬性。如果你沒有,你需要手動釋放自己。你的假設是非常正確的,如果你在財產設置時繼續保留,你會泄漏記憶。

讓我們來思考....在我們使用花式@synthesize聲明之前,屬性過去的樣子是什麼?

id _propertyName; // the ivar 

- (id) propertyName { 
    return _propertyName; 
} 

- (void) setPropertyName:(id)v { 
    if (_propertyName) { 
    [_propertyName release]; // release the previously retained property 
    } 
    _propertyName = [v retain]; // retain this one so it doesn't fly away on us 
} 

現在,你並不需要鍵入這個東西,因爲@synthesize涼爽,產生對你來說,也會產生@synchronized塊,如果你不指定什麼爲nonatomic,這也是相當弧度。

如果您指定assign,而不是retain,你會得到這樣的事情

id _propertyName; // the ivar 

- (id) propertyName { 
    return _propertyName; 
} 

- (void) setPropertyName:(id)v { 
    _propertyName = v; 
} 

這是什麼時候的事情都沒有對象,你唯一可以做的事情,因爲他們只值(有時也稱爲作爲值類型,對象是引用類型)。由於值類型不能保留,其他類型的塊不會有任何意義。繼續嘗試使用BOOL創建retain屬性,並觀察LLVM或GCC告訴你去做什麼;)

0

不應該將這些屬性設置爲 assign?由於設置保留, 當IBOutlet中的保留計數將 增加兩次:一次是當筆尖 加載當 屬性設置另一個時間

好,你發佈的代碼是正確的,因爲它是。

當你使用:

@property (nonatomic, retain) IBOutlet MKMapView *mapView; 

你只是告訴Xcode的創建,這將創造你的MKMapView對象setter方法,每次保留它,你叫

yourMapViewController.mapView = someMapView; // from out 

// or 

self.mapView = someMapView; // from in 

說的MapView後保留數增加+1 和你的MapViewController代碼需要'現在你可以指向mapView並管理它...

不用擔心fo R上的IB榫文件...

當您加載一個UIViewController用筆尖,在你的情況下,類 的MapViewController

:UIViewController中,在IB筆尖對象將當你釋放你的MapViewController釋放... 只關心的你保留的對象...

相關問題