深刻理解屬性、getter及setter

雖然對這個已經很熟了,但是還是看了一遍,生怕遺漏了什麼


轉載自:http://blog.csdn.net/kmyhy/article/details/8571739



原文:http://iphonedevsdk.com/forum/iphone-sdk-tutorials/7295-getters-setters-and-properties-for-the-newbie.html

 

對於有Mac開發經驗的iPhone開發者,可能對O-C的註解“@property”已經習以爲常了。但對於從其他開發平臺(Java或者Symbian)遷移過來的iPhone開發者,“@property”仍然有點麻煩。爲了使這些人不再犯我一樣的錯誤,本文簡單探討了變量及屬性,以及它們所採用的內存管理。

首先來看一個簡單類:

 

//MyClass.h file
@interface MyClass: NSObject
{
    NSString *text;
}

-(void) init;
-(void) logText;
@end

//MyClass.m file
@implementation MyClass

- (void)init
{
    text = @\"sometext\";
}

- (void)logText
{
   NSLog(@\"%@\", text);
}
@end


這個類十分簡單。它唯一的成員就是text,一個NSString。text變量在init方法中初始化,在logText方法中被引用。
就目前而言,text變量中存儲的是常量值,我們無須關心它的內存管理。但在真正的程序中,我們可能會想在運行時改變text的值,因此需要爲它設計getter和setter方法:


//MyClass.h file
@interface MyClass: NSObject
{
    NSString *text;
}

-(void) init;
-(void) logText;
-(NSString*) text;
-(void) setText:(NSString *)textValue;
@end

//MyClass.m file
@implementation MyClass

- (void)init
{
    text = @\"sometext\";
}

- (void)logText
{
   NSLog(@\"%@\", text);
}

-(NSString*) text
{
    return text;
}

-(void) setText:(NSString *)textValue
{
    if (textValue !=text)
    {
       [textValue retain];
       [text release];
       text = textValue;
    }
}

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

@end


接下來,我們需要:
一、添加一個方法,讀取當前的text屬性:

NSString *theTextValue = [obj text];


(假設 "obj" 是一個MyClass實例)

 這個方法很簡單 - 僅僅是返回text屬性值。
二、在另一個方法中,改變text屬性:


    [obj setText:newStringValue];


(假設 "obj" 是一個MyClass實例, "newStringValue" 是一個 NSString).
在setText:方法中,由於我們無法確定newStringValue到底是不是一個常量——它可能是任何NSString值,包括在堆中分配的NSString。因此,我們要“retain”這個(將要賦值給text的)對象,以確保這個對象能夠和MyClass對象的生命週期一樣長。同樣,對於已經被替換掉的舊有值,我們不應當再持有它,因此我們釋放了它。if語句的使用,是爲了減少不必要的賦值——當然,你也可以不用它:


-(void) setText:(NSString *)textValue
{
    [textValue retain];
    [text release];
    text = textValue;
}


即使textValue和text值相同,代碼也會被執行,因爲我們先在引用計數器上+1,然後再減1。注意,這種寫法是錯誤的:
-(void) setText:(NSString *)textValue
{
    [text release];
    [textValue retain];
    text = textValue;
}

 

這是因爲,當“輸入”值和要“持有”的值指向了同一個NSString的情況下,會導致字符串最終將被deallocated——第1句代碼有可能將引用計數減爲0,導致對象被仍會堆裏。第2句代碼試圖去retain這個已經釋放的對象(由於二者是同一個)。這種情況不一定發生,但卻是一個隱患。
最後,我們實現dealloc方法,在其中釋放text對象。我們既然retain了某些東西,就需要記得release它,就好比人臨死的時候,要記得把借的書還給圖書館。
值得注意的是,進行空賦值這些代碼仍然工作得很好。O-C有個奇怪的特點,允許向nil發送消息(比如release和retain消息)而不會出任何錯誤。類似於++ 中可以釋放一個null指針。

現在,更有趣的事情來了。我們將加入第2個成員變量,以及它的getter和setter。很快你就會看到將發生什麼。

//MyClass.h file
@interface MyClass: NSObject
{
    NSString *text;
    int value;
}

-(void) init;
-(void) logText;
-(NSString*) text;
-(void) setText:(NSString *)textValue;
-(int) value;
-(void) setValue:(int*)intValue;
@end

//MyClass.m file
@implementation MyClass

- (void)init
{
    text = @\"sometext\";
    value = 2;
}

- (void)logText
{
   NSLog(@\"%@\", text);
}

-(NSString *) text
{
    return text;
}

-(void) setText:(NSString *)textValue
{
    if (textValue !=text)
    {
       [textValue retain];
       [text release];
       text = textValue;
    }
}

-(int) value
{
    return value;
}

-(void) setValue:(int)intValue
{
    value = intValue;
}

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

@end


這次,我們簡單地加入了一個整型變量以及setter/getter方法。但這次,我們不需要retain 和release 。因爲整型不是在堆中分配的-它直接存儲在MyClass中。我們可以這樣幹:

    NSString *s = [objtext];
    [objsetText:@\"new string\"];
    int i = [obj value];
    [obj setValue:3];

現在,類似的getter/setter方法在O-C中實在是多得讓人寫不勝寫。因此O-C也提供了更簡單的方式爲我們自動生成這些方法。我們可以將上述代碼修改爲:
//MyClass.h file
@interface MyClass: NSObject
{
    NSString *text;
    int value;
}

@property(nonatomic, retain) NSString *text;
@property(nonatomic, assign) int value;

-(void) init;
-(void) logText;
@end

//MyClass.m file
@implementation MyClass

@synthesize text;
@synthesize value;

- (void)init
{
    text = @\"sometext\";
    value = 2;
}

- (void)logText
{
    NSLog(@\"%@\",text);
}

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

@end


首先,在MyClass.h中我們移除了兩個getter方法和兩個setter方法。代之以兩個"@property"開頭的語句。
在 MyClass.m中,我們刪除了所有的setter/getter方法,代之以兩個"@synthesize"開頭的語句。

這和前面的代碼是一模一樣的。 回想一下,寫一個getter也是很簡單的:你只需要知道將返回哪個變量以及變量的類型就行了,這樣就很容易寫出代碼了。對於setter,你需要知道的是:正在對哪個變量賦值,以及它的類型,以及是否是簡單賦值(例如int類型的屬性)或者是否需要進行retain/release(例如NSString屬性)。

然而,現在我們只需要4個"@"語句就行了:

 

@property(nonatomic, retain)NSString *text;

翻譯過來就是“我有一個NSString類型的成員變量 'text'。我需要一對getter/setter方法(使用retain/release)”。

@property(nonatomic, assign) intvalue;

翻譯過來就是“我有一個int型成員變量 'value'。我需要一對使用簡單賦值而不是retain/release的getter/setter方法”。
@synthesize text;

翻譯過來就是“請爲 'text'自動生成getter/setter方法代碼”。
@synthesize value;

翻譯過來就是“請爲 'value'自動生成getter/setter方法代碼”。

注意,我們仍然需要在dealloc方法中release對象。O-C顯然還無法自動幫我們做這些事情。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章