2013-07-23 109 views
1
  1. 在屬性name的getter函數(即自動生成的)中,返回的對象如下所示?屬性/合成對 - 執行getter和setter autorelease對象?

    [self.name autorelease]; 
    return self.name; 
    
  2. 在setter函數(也自動生成的),是retain ED對象autorelease d? -

    - (void) setName : (NSString *) someString { 
        [someString retain]; 
        [name release]; 
        name = someString; 
        /* [someString autorelease]; */ // performed internally? 
    } 
    

#import<Foundation/Foundation.h> 

@interface Dog : NSObject 
{@private NSString * name;} 
@property (nonatomic,retain) NSString * name; 
@end 

@implementation Dog 
@synthesize name; 
- (id) init { 
    self = [super init]; 
    if(self) {} 
    return self; 
} 
@end 

int main(int argc, char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
    Dog * d = [[Dog alloc] init]; 
    [d setName:@"Scooby"]; 
    NSLog(@"Dog's name is: %@",[d name]); 
    [d release]; 
    [pool drain]; 
    return 0; 
} 
+2

順便說一句,蘋果一般建議,(a)您不聲明明確伊娃背喲你的屬性,但讓編譯器爲你做; (b)你不再需要'@ synthesize'行,如果你這樣做了,最好的做法是'@synthesize name = _name;'這樣這個ivar就是'_name',以避免可能的混淆。 (c)在處理字符串時,通常使用'copy'而不是'retain'來安全,所以你不必擔心它會隨着你的變化而變化。 – Rob

+0

請提供(a)和(b)的Objective-C文檔供進一步閱讀。謝謝! – GLES

+1

WWDC 2012會議#405 - 現代Objective-C,約10或11分鐘到視頻。 (不幸的是,由於Apple的安全問題,您可能無法立即訪問WWDC視頻。)但是這段視頻詳細描述了它。 – Rob

回答

2

在回答你的兩個問題:

  1. 吸氣不應該autorelease對象。

  2. 設置者不應該autoreleasesomeString指向的新值的對象。

autorelease是,有效,延期release,所以它不適合無論是getter或二傳手這樣做。當然,制定者會對舊對象進行release,但肯定不應該做新對象的autorelease


順便說一句,三個最終意見:

  • 你不應該寫自己的getter和setter方法,除非有一些迫切需要這麼做。如果你只是想了解他們在做什麼,那很好,但在實踐中,我們很少編寫自己的訪問器方法。

  • 此外,我衷心鼓勵您使用ARC(如果可以的話)。

  • 如果使用Xcode和使用手冊引用計數出於某種原因,絕對通過靜態分析儀運行的代碼(Xcode的「產品」菜單上的「分析」),因爲它會指出許多這些常規的錯誤與autorelease


如果使用帶GNUstep的GCC,你Dog類可能是這樣的:

@interface Dog : NSObject 
{ 
    NSString *_name; 
} 

@property (nonatomic, copy) NSString *name; 

@end 

@implementation Dog 

@synthesize name = _name; 

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

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

@end 

注意,沒有定義訪問方法(他們爲我合成)。

雖然GCC不支持它,如果你使用的是較新的編譯器,你可以省略伊娃聲明和@synthesize行:

@interface Dog : NSObject 

@property (nonatomic, copy) NSString *name; 

@end 

@implementation Dog 

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

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

@end 

或者如果使用ARC,你甚至可以忽略init方法(因爲ARC初始化對象nil)和dealloc方法(因爲ARC顯然會自動釋放的對象):

@interface Dog : NSObject 

@property (nonatomic, copy) NSString *name; 

@end 

@implementation Dog 

@end 
+0

|「autorelease實際上是一個延期發佈,所以它不適合getter或setter這樣做。」 - 那麼什麼是適當的方式;釋放伊娃內dealloc? |「當然,setter會釋放舊的對象,但它肯定不應該做新對象的自動釋放。」 - 所以,正確的方法是「複製''someString'然後釋放它,或者,只是'copy'' someString'而不影響它? – GLES

+0

it = someString – GLES

+1

@GLES是的,如果您正在編寫非ARC代碼,請在'dealloc'中釋放ivar。 (但是你真的應該寫ARC代碼,並且這是爲你完成的。)如果你正在編寫自己的setter(但是除非你有充足的理由這樣做,否則不要那樣做),如果它是'retain'屬性,setter將釋放舊值的對象,並保留新值的對象。如果它是一個'copy'屬性,那麼setter將'釋放'舊的''複製'新的。 – Rob

3

號自動釋放,你問會釋放名稱,導致訪問衝突,因爲在名稱的對象將不被保留。如果在返回對象之前保留對象,getter可以返回一個自動釋放對象:return [[name retain] autorelease] ;.這可能需要完成以支持從多個線程進行訪問,但在這種情況下,某種線程同步需要位於getter和setter中。

爲了讓您的代碼在非ARC中正確,它需要一個釋放名稱的dealloc方法。

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

還有就是自動生成的代碼here的話題進行了一些討論。

+0

|「吸氣劑應該返回一個自動釋放的對象。」 - 以這種方式 - 'return [name autorelease];'或以這種方式 - ' - (void)dealloc {[name release]; [super dealloc];}' – GLES

+1

@GLES不,不要在getter中自動釋放。 (這可能是Brian的回答中的一個錯誤,或者他是在談論Matt關於'atomic'屬性的討論,其中您都保留''和'autorelease';但是_do沒有autorelease without retain_)。與Matt的文章可能的推論相反,使用原子屬性並不確保線程安全。 – Rob

+0

我已經讀過 - 「原子」不會對線程安全做出任何保證 @http://stackoverflow.com/questions/588866/atomic-vs-nonatomic-properties。感謝寶貴的建議! – GLES