I'm getting this warning. What I'm trying to do is have a family of classes and a parallel family of protocols. The class Piece has a declaration like this:
@interface Piece : NSManagedObject <PieceModel>
{
}
...
@property (nonatomic, retain) Player *owner;
...
@end
PieceModel h开发者_JS百科as this
@protocol PieceModel <NSObject>
...
@property (readonly, nonatomic, retain) id <PlayerModel> owner;
@end
And of course:
@interface Player : NSManagedObject <PlayerModel> { ...
It seems to me this should all be totally safe. Users of the protocols see that something conforming to the PieceModel protocol has an owner that should conform to the PlayerModel protocol. And in fact, every instance of the Piece class returns a Player instance for the owner property, which conforms to the PlayerModel protocol. I do see why there is such a warning. It would not be so safe to try to assign any object that conforms to PlayerModel to owner, since it might not belong to the Player class, but that is not a problem in this case because the property is declared as readonly for the protocol.
Notice I also declared the property as retain, which if I am not mistaken is meaningless for a readonly property, but I also got a different warning about a mismatch between the protocol and the class if I didn't do that. At least the compiler does not complain that one property is readonly and the other is not.
I know I could just declare the class property as returning id <PlayerModel>
, but that would be undesirable for a couple reasons. Users of Piece objects that have them statically typed as Pieces would have to do a cast to get something statically typed as a Player. Also, I would have to write the property implementation myself instead of just using @synthesize, or in this case actually @dynamic; Core Data generates the property implementations.
So, can I instruct the compiler to suppress this warning? Or is there a better way to write this code that won't generate the warning?
This generates no warnings ...
@protocol PlayerModel <NSObject>
@end
@protocol PieceModel <NSObject>
- (id<PlayerModel>)owner;
@end
@interface Player : NSObject <PlayerModel> {
}
@end
@interface Piece : NSObject <PieceModel> {
}
@property (nonatomic,retain) Player* owner;
@end
You will then of course not be able to use @synthesize for PieceModel.owner, but that's not so much extra work. Remember that @property declarations are basically just short hand for declaring the setter and getter and defining the behavior of methods generated by @synthesize.
Also keep in mind that dot notation for accessing properties is just syntactic sugar, so if you're fond of dot notation, you'll still be able to use it for accessing 'owner' on variables declared as id<PieceModel>.
Is owner a relationship in your data model? If so, you might find the compiler is confused because NSManagedObject needs to respond to it.
Otherwise, it looks like a limitation of the way properties are handled in subclasses or implementations of protocols. If you replace NSManagedObject by NSObject in Piece and Player and you still get the issue, it might be worth reporting a bug to Apple.
As a work around for the issue, I think you should not declare the property in Piece and declare a separate setter for owner i.e.
@interface Piece : NSManagedObject <PieceModel>
{
}
...
//@property (readonly, nonatomic, retain) id<PlayerModel> owner;
// property declaration not needed because it's in the protocol
-(void) setOwner: (Player*) newOwner;
...
@end
and implement the setter manually.
On an unrelated note, I wouldn't bother declaring properties as nonatomic ever unless I had evidence from a profiler that it provides a significant performance boost.
精彩评论