为什么编译器在子类中重新声明基类的readwrite属性为readonly时会发出警告?

Sli*_*not 6 properties objective-c

后来引用的Apple文档似乎表明这是允许的,尽管我承认从来没有理由在子类中直到现在才这样做.

我有一个带有公共readwrite属性的基类和一个子类,我将该属性重新声明为readonly.子类还有一个类扩展,它再次将该属性重新声明为readwrite,以实现常见的"public readonly,private readwrite"Objective-C模式.但是,我得到以下编译器警告:

warning: Semantic Issue: Attribute 'readonly' of property 'foo' restricts attribute 'readwrite' of property inherited from 'Base'
Run Code Online (Sandbox Code Playgroud)

我在10.7上使用带有LLVM 2.1的Xcode 4.1 build 4B110(尽管LLVM GCC4.2和GCC4.2给出了相同的警告).

这是一个展示编译器警告的精简示例:

#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
Run Code Online (Sandbox Code Playgroud)

以下是Apple的Objective-C编程语言的相关段落:

物业重新声明

您可以在子类中重新声明属性,但是(除了readonly与readwrite之外),您必须在子类中重复其属性.对于在类别或协议中声明的属性也是如此 - 虽然属性可以在类别或协议中重新声明,但属性的属性必须重复.

如果将一个类中的属性声明为readonly,则可以在类扩展(请参阅"扩展"),协议或子类中将其重新声明为readwrite(请参阅"使用属性进行子类化").在类扩展重新声明的情况下,在任何@synthesize语句之前重新声明属性的事实导致合成器被合成.将只读属性重新声明为读/写的能力启用了两种常见的实现模式:不可变类的可变子类(NSString,NSArray和NSDictionary都是示例)和具有只读的公共API的属性类的内部私有readwrite实现.下面的示例演示如何使用类扩展来提供在公共标头中声明为只读的属性,但将其重新声明为read/write.

我一直在类扩展中重新声明公共readonly属性readwrite,但我想我从来没有理由做一个子类.但是,除非我读错了,否则上面的段落似乎表明它是犹太人.任何人都可以让我直接和/或调和文档和编译器之间的明显冲突吗?

我为什么要这样做?当然,我的现实情况更复杂.如果需要的话,我可以进行设计更改以解决这个问题,但这似乎是最不摩擦的替代方案(完全需要这样做是由其他变化驱动).

Tom*_*ing 12

它说你可以重新申报readonly财产,readwrite但你正在做相反的事情.你不能/不应该这样做,因为它可以这样做:

Sub* s = [[[Sub alloc] init] autorelease];
Base* b = s; 
b.foo = YES; //legal for `Base` objects, but not legal for `Sub` objects
Run Code Online (Sandbox Code Playgroud)

这违反了Liskov Substitution Priciple.