2011-08-22 69 views
6

稍後引用的Apple文檔似乎表明這是允許的,儘管我承認直到現在還沒有理由在子類中執行此操作。爲什麼在將子類的readwrite屬性重新聲明爲只讀時,編譯器會發出警告?

我有一個公共讀寫屬性和一個子類,我重新聲明屬性爲只讀的基類。該子類還有一個類擴展,它再次將屬性重新聲明爲readwrite,以實現常見的「public readonly,private readwrite」Objective-C模式。不過,我得到以下編譯器警告:

warning: Semantic Issue: Attribute 'readonly' of property 'foo' restricts attribute 'readwrite' of property inherited from 'Base' 

我使用的Xcode 4.1構建4B110與LLVM 2.1(雖然LLVM GCC4.2和GCC4.2提供相同的警告信息)10.7。

這裏是一個精簡的例子展示了編譯器警告:

#import <Foundation/Foundation.h> 

@interface Base : NSObject 
@property (nonatomic, readwrite) BOOL foo; 
@end 

@implementation Base 
@dynamic foo; 
@end 

// Subclass 
@interface Sub : Base 
@property (nonatomic, readonly) BOOL foo; 
@end 

// Class extension 
@interface Sub() 
@property (nonatomic, readwrite) BOOL foo; 
@end 

@implementation Sub 
@dynamic foo; // it warns with @synthesize as well 
@end 

下面是來自蘋果的The Objective-C Programming Language相關通道:

屬性重複

您可以在重新聲明屬性子類,但(除了 只讀與讀寫之外),您必須在 之後重複其整體屬性他的子類。 類別或協議中聲明的屬性也是如此 - 雖然該屬性可能在類別 或協議中重新聲明,但必須重複整個屬性的屬性。

如果您爲只讀聲明一個類的屬性,你可以在子類中重新聲明它 作爲一個類擴展讀寫(見「擴展」),在協議或 (參見「子類與屬性」) 。對於類別 擴展重新聲明,事實上該屬性在 之前重新聲明爲任何@synthesize語句會導致合成器被合成。 將只讀屬性重新聲明爲讀/寫的能力啓用了兩個公共實現模式:不可變類 (NSString,NSArray和NSDictionary都是示例)的可變子類以及 具有公共API的屬性是隻讀的,但是類內部的私有讀寫實現 。以下示例顯示使用類擴展 提供在公共標題 中聲明爲只讀的屬性,但被私下重新聲明爲讀/寫。

我重新聲明公共readonly屬性readwrite在類擴展中,但我想我從來沒有理由做它的子類。但是,除非我讀錯了,否則上面的段落似乎表明它是猶太教。任何人都可以讓我直接和/或協調文檔和編譯器之間的明顯衝突嗎?

爲什麼我要這樣做?當然,我的現實世界更加複雜。如果需要,我可以進行設計更改以解決此問題,但這似乎是最少摩擦的替代方案(完全需要這樣做是由其他更改引發的)。

回答

10

它說你可以重新聲明一個readonly屬性爲readwrite,但你做的是相反的。你不能/不應該,因爲這是可能做到這一點做到這一點:

Sub* s = [[[Sub alloc] init] autorelease]; 
Base* b = s; 
b.foo = YES; //legal for `Base` objects, but not legal for `Sub` objects 

這是違反了the Liskov Substitution Priciple的。

+0

湯姆說了些什麼。當超類提供公開的讀寫時,只讀取子類是沒有意義的。通常,您可以添加沿類層次結構的可變性(請參閱OS中提供的各種不可變 - >可變類集羣示例)。 – bbum

+0

謝謝湯姆和寶貝。我(應該)更好地瞭解。我想我這個週末花了太多時間來思考我的實際問題,忽視了最初的原則。我甚至有第二次抓住自己的機會,但是我的大腦通過多次閱讀以某種方式在文檔第二段中「或者在一個子類中」被過濾出來。晚餐休息後,回到你的答案,我覺得這個有點傻。感謝一些清晰的,我喜歡Liskov鏈接! – Slipknot

相關問題