2009-08-18 77 views
6

今天早上我遇到了一個iPhone應用程序崩潰,當我修復這個bug時,我很好奇它是一個問題的句法原因。在不使用自引用的情況下設置Objective-C類屬性

這裏是我的代碼簡化爲簡單的元素。我使用NSArray爲項目填充TableView中的項目。該NSArray的是一個屬性:

@interface FooViewController : UITableViewController { 
    NSArray *stuff; 
} 

@property (nonatomic, retain) NSArray *stuff; 

在我的實現文件:

@synthesize stuff; 

- (void)viewDidLoad {  
    NSArray *arr = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    self.stuff = arr; 

    [arr release]; 
} 

現在,當我第一次寫的方法,我不小心不放過的「自我」。並導致了炸彈。雖然在測試時,它一開始就表現出色。我會嘗試:用東西在轟炸其他方法

stuff = arr; 
NSLog(@"%d", [stuff count]); 

不過。現在我已經解決了這個問題,我可以在其他地方使用[stuff count]。

那麼,爲什麼我可以在一些地方使用東西但在其他地方我必須使用self.stuff

回答

4

這還努力正確:

- (void)viewDidLoad {  
    stuff = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
} 

因爲數組被ALLOC保留。但它通常是更好地堅持以點符號,如果你有一個屬性,並使用自動釋放陣列創建方法,你在哪裏得到保留「免費」從屬性:

- (void)viewDidLoad {  
    NSArray *arr = [NSArray arrayWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    self.stuff = arr; 

} 

你可能只是離開它,以保持事情簡單,但你也需要釋放該數組中的dealloc:

- (void)dealloc {  
    [stuff release]; stuff = nil; 
} 
+1

如果您打算使用屬性,那麼您應該在任何地方使用它們,即dealloc內容應該簡單地讀取: self.stuff = nil; 幫助避免出錯的常用方法是聲明實例變量: NSArray * _stuff; 屬性聲明保持不變,但合成語句現在應該如下所示: @synthesize stuff = _stuff; 現在,每次嘗試使用沒有自己的東西時,編譯器都會標記錯誤。 – 2010-02-08 09:41:37

+1

實際上Apple建議在dealloc中直接釋放類變量,而不是使用屬性 - 這是因爲如果使用屬性,可能會觸發KVC通知,或者可能會通過覆蓋合成的get/set方法啓動其他副作用。 – 2010-02-08 20:18:05

+0

感謝您的提示。我想知道這是如何相關,特別是因爲可能不想* KVO觸發?更不用說在現代運行時中,我們將*擁有使用訪問器和合成實例變量的機會。我想蘋果正在確保他們的代碼能夠抵禦這種情況。到目前爲止,我還沒有遇到任何與我的代碼有關的問題,但是現在我已經警告過了:-) – 2010-02-21 23:50:15

3

stuff = ...直接引用屬性的後臺字段。它不會增加保留計數。因此,在其他地方釋放對象可能會將其保留計數降至零,並在您仍然參照它時釋放該對象。此外,它可能會導致內存泄漏的屬性的以前的值。
它看起來像工作的原因有時是該對象可能還沒有被其他人釋放。

另一方面,self.stuff = ...將發送一條消息到屬性的set訪問器,該訪問器將負責保留計數。

5

當你使用(self)和點語法時,給定你定義屬性的方式(nonatomic,retain),保留NSArray(stuff)。

當你不這樣做時,你仍然在做這個任務,但是你不是通過alloc + init保留數組,而是通過alloc + init保留數組,並且你馬上釋放它。

讓您可以通過操作的方式從「self.stuff = ARR」分配:

stuff = [arr retain]; 

但既然你定義的屬性,你顯然要使用點語法和具有挽留你調用。

3

做的區別:

stuff=arr; 

self.stuff=arr; 

是在第二種情況下,您實際上正在調用自動​​合成的setStuff:accessor方法,該方法保留了該數組。在你發佈的代碼中,數組是使用alloc/initWithObjects創建的,因此它的保留計數爲1.

你只需要改變在你的viewDidLoad方法中刪除對[arr release]的調用,一切都會好起來的:

- (void)viewDidLoad {  
    NSArray *arr = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    stuff = arr; 
} 

正如你注意到的,你也可以通過使用self.stuff來「修復」這個。我建議不要這樣做,因爲它掩蓋了代碼的含義,並添加了大多數情況下不需要的額外工作。一般來說,我建議不要使用「自我」。語法在您的實例方法中。

+0

因此,如果@property具有'assign'語義,那麼在訪問前不使用'self.'確實可以嗎? – bobobobo 2012-09-08 21:03:47

+0

一般來說,是的。正如在其他答案中提到的那樣,直接訪問屬性不會激發KVO觀察員,(這可能是也可能不是理想的,具體取決於)。 – 2012-09-11 23:29:46

相關問題