2011-06-23 70 views
4

在下面的共同的樣品,Objective-C中,接口聲明具有屬性

//// 
@interface MyObject : NSObject 
{ 
@public 
    NSString * myString_; 
} 

@property (assign) NSString * myString; 
@end 

@implementation MyObject 
@synthesize myString = myString_; 
@end 
//// 

爲什麼聲明在界面在所有myString_

我問,因爲我們仍然可以獲取和使用self.myString[self myString]self.myString = ...[self setMyString:...]實施設置myString。事實上,我們必須相反,如果它被保留。

回答

1

隨着現代的Obj-C運行時間,聲明伊娃比其他任何形式更具形式性。但是,有一些內存管理事項需要記住。

首先,對象類型的屬性聲明通常是retain,或者對於字符串,它可能是copy。無論哪種情況,都會保留新對象。

鑑於以下代碼:

NSString *string = [[NSString alloc] init]; 
myString_ = string; 
self.myString = string; // If the property was retain or copy 

第二分配會泄漏;第一個不會。這是因爲該屬性會保留已有保留計數爲1的東西 - 現在爲2.當您釋放dealloc中的屬性時,計數將變爲1,而不是0,因此它不會被釋放。然而,有了第一個選項,保留計數保持爲1,因此dealloc將其降爲0.

在您的示例中,將屬性保留爲assign將使伊娃聲明成爲正式。

5

這是一些偏好/約定的問題。默認情況下,這樣做的:

@property (assign) NSString * myString; 

...依次爲:

@synthesize myString; 

...會給你三件事情。你會得到一個setter方法,它可以被訪問爲self.myString = @"newValue"[self setMyString:@"newValue"],一個可以作爲NSString* temp = self.myStringNSString* temp = [self myString]訪問的getter方法,以及一個名爲myString的實例變量,它們可以直接在你的類的內部訪問(即不經過getter和setter )並用於設置和獲取屬性值,並在內部用於支持該屬性。

如果你喜歡,你可以做@synthesize myString = someOtherVarName,然後你還是像以前一樣得到getter和setter方法,但不是在myString實例變量someOtherVarName實例變量是用來備份的財產,並沒有創建myString變量。

那麼爲什麼要使用更冗長的語法呢?從來沒有任何情況要求您這樣做,但有些人在處理聲明爲retaincopy的屬性時更願意這樣做。原因是設置一個通過其生成的setter方法聲明爲retaincopy的屬性將影響被設置/取消設置的對象的保留計數。通過直接訪問實例變量來做同樣的事情不會。

因此,通過將實例變量別名爲別的,您可以在代碼中沿着「xxx.myString = Y修改保留計數的任何內容進行區分,而someOtherVarName = Y的任何內容都不是」。再次,沒有必要這樣做,但有些人更喜歡。

+1

+1;我想補充一點,'@ synthesize'只會使用ivar,getter和setter完成這個類:如果你自己定義了它們,它們將優先於自動實現。 – zneak

2

你應該可以跳過它。現代編譯器允許這樣做。

當你定義一個屬性時,你實際上是在聲明如何爲特定的實例變量構造getter和setter方法。之前它需要定義實例變量,以便您聲明它。它還允許屬性名稱通過@synthesize myProperty = myIVar;與實例變量名稱不同。現在你不需要這樣做,因爲現代編譯器會爲你生成實例變量。

點語法實際上是一個方便的東西,因爲你會注意到。它不直接引用實例變量,而是直接引用方法myPropertysetMyProperty:。你甚至可以打電話myArray.count,其中count不是一個屬性(我不會推薦它,即使很多人似乎喜歡它)。

雖然兩者之間存在差異,但差距似乎在緩慢收尾。

2

這只是一個關於觀點的問題。如果您直接訪問伊娃,那麼您就是在內部訪問它。如果你使用財產,你沒有訪問伊娃(語義)。您正在使用對象的訪問方法。所以你正在處理self就像內部未知的外部對象。

這是封裝面向對象範例的問題。

我在使用屬性時推薦一些技巧。

  1. ivar聲明是可選的,不是必需的。編譯器會自動生成它。
  2. 您應該將伊娃設置爲@protected@private以正確地封裝它。 (至少沒有合理的理由)
  3. 如果您在訪問屬性時不需要線程鎖定,我建議使用nonatomic。線程鎖定會極大地降低性能,並可能導致併發執行代碼中的奇怪行爲。

您可以使用此代碼做同樣的事情。

@interface MyObject : NSObject 
@property (assign,nonatomic) NSString * myString; 
@end 

@implementation MyObject 
@synthesize myString; 
@end 

而且這將會大致變成這樣。

@interface MyObject : NSObject 
{ 
    @private 
    NSString* myString; // Ivar generated automatically by compiler 
} 
@end 

@implementation MyObject 
// Methods with thread synchronization locking generated automatically by compiler. 
- (NSString*)myString { @synchronized(self) { return myString; } } 
- (void)setMyString:(NSString*)newMyString { @synchronized(self){ myString = newMyString; } } 
@end 

其實,我不知道有assign行爲指令同步鎖,但它總是更好的設置它nonatomic明確。編譯器可以使用原子操作指令而不是鎖定來優化它。

以下是有關屬性的參考文件:http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html%23//apple_ref/doc/uid/TP30001163-CH17