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

时间:2011-08-22 01:38:09

标签: objective-c properties

后来引用的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'

我在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

以下是Apple The Objective-C Programming Language的相关段落:

  

财产重新申报

     

您可以重新声明子类中的属性,但(除了   readonly与readwrite)你必须重复其属性   子类。对于在a中声明的属性也是如此   类别或协议 - 而财产可以在一个类别中重新申报   或协议,属性的属性必须重复。

     

如果您将一个类中的属性声明为readonly,则可以重新声明它   作为类扩展中的读写(请参阅“扩展”),在协议中,或   在子类中(请参阅“使用属性进行子类化”)。在班级的情况下   延期重新申报,事先已重新申报该财产   任何@synthesize语句都会导致setter被合成。该   能够重新声明只读属性作为读/写启用两个   常见的实现模式:不可变类的可变子类   (NSString,NSArray和NSDictionary都是示例)和一个属性   有一个只读的公共API,但是私有的readwrite实现   课堂内部。以下示例显示了使用类扩展   提供在公共标头中声明为只读的属性   但是在读/写时被私下重新声明。

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

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

1 个答案:

答案 0 :(得分: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

这违反了the Liskov Substitution Priciple