2010-10-28 68 views
7

我想了解如何設置屬性(訪問器)的參數。初始化器,屬性,訪問器和複製/保留/只讀

我從一個Kal日曆的例子中拿了下面的代碼。

// Holiday.h 

@interface Holiday : NSObject 
{ 
    NSDate *date; 
    NSString *name; 
    NSString *country; 
} 

@property (nonatomic, retain, readonly) NSDate *date; 
@property (nonatomic, retain, readonly) NSString *name; 
@property (nonatomic, retain, readonly) NSString *country; 

- (id)initWithName:(NSString *)name country:(NSString *)country date:(NSDate *)date; 

@end 

// Holiday.m 

#import "Holiday.h" 

@implementation Holiday 

@synthesize date, name, country; 

- (id)initWithName:(NSString *)aName country:(NSString *)aCountry date:(NSDate *)aDate 
{ 
    if ((self = [super init])) { 
    name = [aName copy]; 
    country = [aCountry copy]; 
    date = [aDate retain]; 
    } 
    return self; 
} 

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

@end 

1)屬性設置爲retain,但由於二傳手不能使用retain使得這裏沒有任何意義。

2)另外,在initWithName方法中,值設置爲copy。爲什麼不直接用copy定義屬性並使用訪問器方法?

@property (nonatomic, copy) NSString *name; 
// ... 
self.name = aName; 

3)我需要readonly嗎?我不知道他們爲什麼在這裏使用。如果我將copy與設置器一起使用,則readonly禁止我設置該值,因爲沒有設置器。

4)在initWithName方法中有時使用copy,有時使用retain。我建議在這裏始終使用copy,因爲這個值不應該在以後修改。

5)我能記住的是,它是確定在dealloc方法initWithNamereleasecopy/retain

那麼你會如何建議在這個例子中使用retain,copyreadonly

回答

13

ETA: @DougW正確地指出,財產的所有權類型(assign/retain/copy)不影響吸氣。它仍然影響着二傳手。對於readonly類型,如果要在類擴展中覆蓋聲明的readonly部分,則這很重要,因此您可以在實現中使用setter。類擴展屬性覆蓋僅允許更改屬性的狀態,因此其餘部分(即原子性和所有權類型)必須在標頭中正確聲明。即使你現在不覆蓋這個屬性,你也可能在將來,所以你也可以通過使用正確的選項來記錄你想要爲自己管理的內存。

自動引用計數(ARC)通過在自己的內存管理規則上覆蓋傳統的引用規則來更改運行時實現細節,但用於配置屬性的規則和建議保持不變。


爲什麼要用retainreadonly如果標記屬性作爲retain,合成的訪問做這樣的事情:

/* getter for retain property */ 
- (NSString *)name { 
    return [[name retain] autorelease]; 
} 

現在,如果你發送的對象-name來,而你還在使用它改變了名稱,調用代碼仍會有對字符串的有效引用。如果你宣佈它爲assign,不過,這將是這樣的:

/* getter for assign property */ 
- (NSString *)name { 
    return name; 
} 

現在,只要名字被更改的對象,它必須被釋放,以避免泄漏,這將無效調用代碼的參考。 retain/copy/assign確實陳述了一個內存管理策略:retain/copy說,「我保證我持有一個原始/我在這裏提供的值的副本的參考,」而assign說,「我只是有價值並聲稱沒有對此的參考。「

當該值不需要內存管理時,如普通的int,則assign是有意義的。當你故意不保留一個對象,例如代表,那麼assign是有道理的。但是,在其他大多數情況下,您需要retaincopy

此外,實現文件只能覆蓋屬性聲明的readwrite/readonly部分,而不是內存管理部分。至於宣佈,該.m文件可以有:

用於重寫的屬性聲明
@interface Holiday (/*class extension*/) 
@property(nonatomic, retain, readwrite) NSDate *date; 
/* override other properties to make them readwrite... */ 
@end 

非公有制制定者隨後將與公衆存取一起合成。

爲什麼不在-init期間使用setter/accessors?由於setter/accessor經常執行KVO通知,當您的對象未完全初始化時(即,在-init(當它在完全初始化的途中半初始化時)和-dealloc(當其初始化爲半初始化時)完全未初始化的方式)。

爲什麼要用copyreadonly至於迴應你的第一個問題:因爲如果copyretain相比assign同時影響了制定者和獲得者。副本的getter應該是這樣的:

/* getter for copy property */ 
- (NSString *)name { 
    return [[name copy] autorelease]; 
} 

爲何有時copy有時retaincopy通常與值對象(代表值的被動對象)一起使用; retain通常與其他對象一起使用。有時候,效率問題開始起作用(很可能過早......),並且您可能會選擇使用retain,您通常會使用copy

您會如何在此處使用copy/retain以及readonly和他們一樣。我會重寫類擴展中的聲明,以便我可以使用setter來更改-init-dealloc之外的屬性值,其中我只使用直接實例變量訪問。我也要nil了釋放他們-dealloc,例如後的高德,

[name release], name = nil; 

這有助於避免將消息發送到或以其他方式引用一個已經釋放的對象。

+0

** nonatomic **保留屬性只是返回指針。他們**不**做保留,autorelease的事情。請參閱文檔http://developer.apple的**原子性**部分。com/library/ios /#documentation/cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html – JeremyP 2010-10-28 15:56:34

+0

@JeremyP:好的呼叫。不在非原子訪問器中'[[保留] autorelease]'的決定是有道理的:如果你想要保持比當前runloop週期更長的值,你應該自己保留它。如果你使用'nonatomic',你基本上是說線程安全不是問題。如果你不必擔心線程安全性,那麼當你使用來自訪問器的返回值時,除了你的代碼之外,沒有任何代碼會被執行,所以訪問器不需要執行'[[foo retain] autorelease] 。 – 2010-10-28 16:04:27

+0

@Jeremy:我甚至會說使用非原子意味着你說健壯不是一個問題 - 或者比性能更不重要。如果沒有首先分析代碼,將屬性設置爲非原子計數在我的書中算是過早的優化。 – JeremyP 2010-10-28 16:15:53