我有一个带有公共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的相关段落:
Property Redeclaration
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.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.
我一直在类扩展中重新声明公共readonly属性readwrite,但我想我从来没有理由做一个子类.但是,除非我读错了,否则上面的段落似乎表明它是犹太人.任何人都可以让我直接和/或调和文档和编译器之间的明显冲突吗?
我为什么要这样做?当然,我的现实情况更复杂.如果需要的话,我可以进行设计更改以解决这个问题,但这似乎是最不摩擦的替代方案(完全需要这样做是由其他变化驱动).
解决方法
Sub* s = [[[Sub alloc] init] autorelease]; Base* b = s; b.foo = YES; //legal for `Base` objects,but not legal for `Sub` objects