【问题标题】:Objective-C: "warning: property 'owner' type does not match protocol 'PieceModel' property type"Objective-C:“警告:属性‘所有者’类型与协议‘PieceModel’属性类型不匹配”
【发布时间】:2011-03-31 07:07:13
【问题描述】:

我收到此警告。我想要做的是有一个类族和一个并行的协议族。 Piece 类有这样的声明:

@interface Piece : NSManagedObject <PieceModel>
{
}

...

@property (nonatomic, retain) Player *owner;

...

@end

PieceModel 有这个

@protocol PieceModel <NSObject>

...

@property (readonly, nonatomic, retain) id <PlayerModel> owner;

@end

当然还有:

@interface Player : NSManagedObject <PlayerModel> { ...

在我看来,这一切都应该是完全安全的。协议的用户看到符合 PieceModel 协议的东西有一个应该符合 PlayerModel 协议的所有者。事实上,Piece 类的每个实例都为 owner 属性返回一个 Player 实例,它符合 PlayerModel 协议。我明白为什么会有这样的警告。尝试将任何符合 PlayerModel 的对象分配给所有者并不是那么安全,因为它可能不属于 Player 类,但在这种情况下这不是问题,因为该属性被声明为协议的只读。

请注意,我还将该属性声明为保留,如果我没记错的话,这对于只读属性是没有意义的,但如果我不这样做,我也会收到关于协议和类之间不匹配的不同警告。至少编译器不会抱怨一个属性是只读的而另一个不是。

我知道我可以将类属性声明为返回 id &lt;PlayerModel&gt;,但出于几个原因,这是不可取的。将 Piece 对象静态类型为 Pieces 的用户必须进行强制转换才能获得静态类型为 Player 的东西。另外,我必须自己编写属性实现,而不仅仅是使用@synthesize,或者在这种情况下实际上是@dynamic; Core Data 生成属性实现。

那么,我可以指示编译器抑制这个警告吗?或者有没有更好的方法来编写不会生成警告的代码?

【问题讨论】:

    标签: objective-c xcode warnings suppress-warnings


    【解决方案1】:

    这不会产生任何警告...

    @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
    

    您当然不能将@synthesize 用于 PieceModel.owner,但这并没有太多额外的工作。请记住,@property 声明基本上只是声明 setter 和 getter 以及定义 @synthesize 生成的方法行为的简写。

    还请记住,用于访问属性的点表示法只是语法糖,所以如果您喜欢点表示法,您仍然可以使用它来访问声明为 id 的变量的“所有者” .

    【讨论】:

    • 不,然后我得到:警告:类'Piece'没有完全实现'PieceModel'协议警告:未找到'-owner'的方法定义警告:类'Piece'的不完整实现@ 987654322@ 与@property (readonly) id &lt;PlayerModel&gt; owner; 相同,但编译器似乎不够聪明,无法在类符合协议的情况下弄清楚这一点。即使我声明 PieceModel 为:@protocol PieceModel -(Player *)owner; @end 我不想这样做,我得到了同样的警告。
    • 嗯,我尝试了其他方法,您的解决方案似乎有效,但不适用于属性的 @dynamic 定义。
    • 正确。我的建议特别避免在 PieceModel 协议中声明 @property。
    【解决方案2】:

    所有者在您的数据模型中是一种关系吗?如果是这样,你可能会发现编译器很困惑,因为 NSManagedObject 需要响应它。

    否则,在子类或协议实现中处理属性的方式似乎受到限制。如果您在 Piece and Player 中将 NSManagedObject 替换为 NSObject 并且仍然遇到问题,那么可能值得向 Apple 报告错误。

    作为解决该问题的方法,我认为您不应该在 Piece 中声明该属性并为所有者声明一个单独的设置器,即

    @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
    

    并手动实现设置器。

    在不相关的说明中,我不会费心将属性声明为非原子的,除非我有来自分析器的证据表明它提供了显着的性能提升。

    【讨论】:

    • 是的,所有者是数据模型中的关系。似乎这可能是问题的一部分。如果我提供如下访问器的实现,imaginaryboy 的建议会消除与此问题相关的警告: -(Player *)owner { ... } -(void)setOwner:(Player *)owner { ... }如果我使用 @dynamic 关键字来指示 Core Data 将提供访问器,它就不起作用。编译器不知道正确的访问器将存在。但是@dynamic 不应该通知编译器该类将完全像上面那样响应选择器吗?
    • 我尝试了你的建议,它确实消除了警告,但也有一些缺点。首先,理论上,具有静态类型 Piece 对象的代码可能希望在没有强制转换的情况下以 Player 而不是 PlayerModel 访问所有者。其次,有一部分是关于我自己编写 setter 的,我可以这样做,但我不希望这个和其他几个我有类似问题的类。它按原样工作;我真的只是想摆脱我收到的几十个警告。这些虚假警告让我很容易错过重要警告。
    • 好吧,很抱歉,您似乎在要求语言做它不能做的事情。坦率地说,我认为您使用协议镜像数据模型的想法是错误的。每次更改数据模型时,都必须手动更改受影响的协议以及自定义托管对象。这听起来像是一场维护噩梦。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-18
    • 2013-12-22
    • 2012-09-05
    • 2014-10-26
    • 2021-10-15
    • 2013-03-22
    • 1970-01-01
    相关资源
    最近更新 更多