2013-05-30 47 views
1

它是一個更好的做法,在二傳,保留和釋放的NSString如下:Objective-C的 - 的NSMutableString了setString VS的NSString

-(void) setName:(NSString *)newName 
{ 
    if(newName != nil) 
    { 
     [newName retain]: 
     [m_Name release]; 
     m_Name = newName; //Where m_Name is a NSString * 
    } 
    //I'm not sure for this code, I have difficulties understanding memory-management in ObjC 
} 

或者改變通過的NSMutableString值:

-(void) setName:(NSString *)newName 
{ 
    if(newName != nil) 
     [m_Name setString:newName]; //Where m_Name is a NSMutableString * 
} 

如果任何一個或兩個方法都不正確,請告訴我。

+3

你爲什麼要實現自己的「setter」方法?除非您在此發佈的內容除非您實際上有其他處理方式,否則沒有必要執行此操作。 – rmaddy

+2

@maddy我敢打賭,OP是從一個過時的教程或書籍工作。 – bbum

回答

3

一對夫婦的想法:

  1. 最好的做法是不寫setter方法可言,採取的自動合成存取方法的優勢)。編寫你自己的只是一個搞亂內存管理或引入錯誤的機會。在寫一個自定義setter之前,你應該有一個引人注目的需求。

  2. 實例變量名稱的新興慣例是使用前面帶有下劃線的屬性名稱(例如,對於稱爲name的財產,伊娃爲_name)。如果您省略了@synthesize語句,則最新版本的Xcode附帶的編譯器會自動爲您執行此操作。

  3. 在沒有說明你的財產有什麼記憶限定符的情況下,設置者應該是什麼的問題是沒有意義的。我假設你將你的財產定義爲retain

  4. 將屬性更改爲NSMutableString會改變屬性的行爲,我不會建議,除非您確實需要可變字符串。

  5. 如果有人將name屬性設置爲nil,則第一個示例不會執行任何操作。但是如果有人想將其設置爲nil,則應該(a)釋放舊的name值;和(b)將你的伊娃放入nil。 (順便說一句,下面的代碼利用了將消息發送到nil對象沒有任何作用的事實,所以在這種情況下,我不需要檢查它是否爲nil。)

所以,我假設你有一個屬性定義如下:

@property (nonatomic, retain) NSString *name; 

和合成線被省略或看起來像:

@synthesize name = _name; 

然後,我想二傳手將如下所示:

-(void) setName:(NSString *)name 
{ 
    // if you want to program defensively, you might want the following assert statement: 
    // 
    // NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__); 

    if (name != _name) 
    { 
     [_name release]; 
     _name = name; 
     [_name retain]; 
    } 
} 

順便說一句,我假設你的init方法正確初始化_namedealloc釋放它。

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     _name = nil; 
    } 
    return self; 
} 

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

由於bblum指出,這是謹慎使用copyNSString屬性:

@property (nonatomic, copy) NSString *name; 

然後,我覺得二傳手會是什麼樣子:

-(void) setName:(NSString *)name 
{ 
    // if you want to program defensively, you might want the following assert statement: 
    // 
    // NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__); 

    if (name != _name) 
    { 
     [_name release]; 
     _name = [name copy]; 
    } 
} 

但真的,除非你絕對需要,否則你根本不應該寫西班牙文。


最後,您的代碼有關於查找內存管理混淆的註釋。雖然你一定要明白,我會做最後兩個建議:

  1. 考慮使用Automatic Reference Counting(ARC)。雖然這並不排除理解內存管理如何工作的需要(請參閱Advanced Memory Management Programming Guide),但它確實可以更輕鬆地編寫正確處理內存管理的代碼。如果您編寫手動引用計數(MRC)代碼,那麼可以很容易地發生簡單的內存管理錯誤,否則ARC會爲您處理這些錯誤。

  2. 特別是如果你要(以下簡稱「產品」菜單上的「分析」或按轉變 + 命令 + )使用MRC,利用自己的Xcode的靜態分析儀。這可以促進尋找困擾MRC代碼的許多常規內存管理問題。 儀器用戶指南Finding Memory Leaks部分也說明了如何在調試代碼時發現泄漏,但通常靜態分析器只能通過檢查代碼來識別問題。

+0

'NSString'' @ property'聲明應該總是'copy',而不是'retain'。這是對'foo.bar = someMutableString;'的防禦。另外,*我認爲*您的setter實現最終會在這種情況下生成兩個KVO通知,因爲標準setter將自動與KVO兼容。 – bbum

+0

@bbum同意這兩點,我已經相應地更新了我的答案。 – Rob

0

第一種解決方案更好。這是如何處理retain屬性的。您保留新值,然後釋放舊值。另外,如果nil案件不是至關重要的處理,您可以依靠由@synthesize生成的默認實現。

對於第二種解決方案來說,這確實沒有必要,而且這有點違背慣例。此外,在此解決方案中,您必須在爲其分配任何字符串之前初始化m_name。你可以在init中這樣做。

- (void) init { 
    if (self = [super init]) { 
     m_name = [[NSMutableString alloc] init]; 
    } 
} 

結論:第一種方法是肯定更好。

相關問題