为什么在子类中将基类的 readwrite 属性重新声明为 readonly 时编译器会发出警告? [英] Why does the compiler warn when redeclaring base class's readwrite property as readonly in subclass?
问题描述
后来引用的 Apple 文档似乎表明这是允许的,尽管我承认直到现在才没有理由在子类中这样做.
The Apple doc quoted later seems to indicate this is permissible, though I'll admit never having a reason to do it in a subclass until now.
我有一个带有公共读写属性的基类和一个子类,我在其中将该属性重新声明为只读.子类还有一个类扩展,它再次将属性重新声明为读写,以实现常见的公共只读,私有读写"Objective-C 模式.但是,我收到以下编译器警告:
I have a base class with a public readwrite property and a subclass where I redeclare the property as readonly. The subclass also has a class extension which again redeclares the property as readwrite to achieve the common "public readonly, private readwrite" Objective-C pattern. However, I get the following compiler warning:
warning: Semantic Issue: Attribute 'readonly' of property 'foo' restricts attribute 'readwrite' of property inherited from 'Base'
我在 10.7 上使用 Xcode 4.1 build 4B110 和 LLVM 2.1(尽管 LLVM GCC4.2 和 GCC4.2 给出了相同的警告).
I'm using Xcode 4.1 build 4B110 with LLVM 2.1 (though LLVM GCC4.2 and GCC4.2 give the same warning) on 10.7.
这是一个显示编译器警告的精简示例:
Here's a stripped-down example which exhibits the compiler warning:
#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 <的相关段落em>Objective-C 编程语言:
Here's a relevant passage from Apple's The Objective-C Programming Language:
财产重新申报
您可以重新声明子类中的属性,但是(除了只读与读写)您必须在整个中重复其属性子类.这同样适用于在 a 中声明的属性类别或协议——虽然该属性可以在类别中重新声明或协议,属性的属性必须完整重复.
You can redeclare a property in a subclass, but (with the exception of readonly versus readwrite) you must repeat its attributes in whole in the subclasses. The same holds true for a property declared in a category or protocol—while the property may be redeclared in a category or protocol, the property’s attributes must be repeated in whole.
如果你在一个类中声明一个属性为只读,你可以重新声明它作为类扩展(参见扩展")、协议中的读写,或在子类中(请参阅使用属性进行子类化").在班级的情况下延期重新申报,即财产在之前重新申报的事实任何@synthesize 语句都会导致 setter 被合成.这重新声明只读属性作为读/写的能力启用两个常见实现模式:不可变类的可变子类(NSString、NSArray 和 NSDictionary 都是示例)和一个属性有一个只读的公共 API,但有一个私有的读写实现班级内部.以下示例显示使用类扩展提供在公共标头中声明为只读的属性但被私下重新声明为读/写.
If you declare a property in one class as readonly, you can redeclare it as readwrite in a class extension (see "Extensions"), in a protocol, or in a subclass (see "Subclassing with Properties"). In the case of a class extension redeclaration, the fact that the property was redeclared prior to any @synthesize statement causes the setter to be synthesized. The ability to redeclare a read-only property as read/write enables two common implementation patterns: a mutable subclass of an immutable class (NSString, NSArray, and NSDictionary are all examples) and a property that has a public API that is readonly but a private readwrite implementation internal to the class. The following example shows using a class extension to provide a property that is declared as read-only in the public header but is redeclared privately as read/write.
我一直在类扩展中重新声明公共只读属性 readwrite,但我想我从来没有理由将它作为子类.但是,除非我读错了,否则上面的段落似乎表明它是犹太洁食.任何人都可以让我直截了当地和/或调和文档和编译器之间的明显冲突吗?
I redeclare public readonly properties readwrite in class extensions all the time, but I guess I've never had cause to do it an a subclass. However, unless I'm reading it wrong, the paragraphs above seem to indicate that it's kosher. Can anyone set me straight and/or reconcile the apparent conflict between the docs and the compiler?
我为什么要这样做?当然,我的实际情况更复杂.如果需要,我可以进行设计更改以解决此问题,但这似乎是摩擦最小的替代方案(完全需要这样做是由其他更改驱动的).
Why do I want to do this? My real-world situation is more complex, of course. I can make design changes to work around this if needed, but this seemed like the least-friction alternative (the need to do this at all is being driven by other changes).
推荐答案
它说你可以将 readonly
属性重新声明为 readwrite
,但你正在做相反的事情.你不能/不应该这样做,因为有可能这样做:
It says you can redeclare a readonly
property as readwrite
but you're doing the opposite. You can't/shouldn't do it because it's possible to do this:
Sub* s = [[[Sub alloc] init] autorelease];
Base* b = s;
b.foo = YES; //legal for `Base` objects, but not legal for `Sub` objects
这违反了Liskov 替换原则.
这篇关于为什么在子类中将基类的 readwrite 属性重新声明为 readonly 时编译器会发出警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!