【问题标题】:Can a category simultaneously implement a protocol?一个类可以同时实现一个协议吗?
【发布时间】:2009-11-01 00:02:42
【问题描述】:

如果我为一个类创建的类别添加了也履行协议规定的合同的方法,我想将该类别类标记为实现该协议,从而向 Obj-C pre-处理器,该类也有效​​地实现了协议。

示例委托(为清楚起见,感谢 Ole!):

@protocol SomeDelegate <NSObject>
  - (void)someDelegateMessage;
@end

示例类别:

@interface NSObject (SomeCategory) <SomeDelegate>
  - (void)someDelegateMessage;    
@end

还有一个典型的实现

@implement NSObject (SomeCategory)
  - (void)someDelegateMessage {}
@end

当我实际尝试这个时,我会收到每个 NSObject 方法的警告:

警告:类别“SomeCategory”的实施不完整

警告:未找到“-description”的方法定义

...

警告:'-isEqual:' 的方法定义未找到

警告:类别“SomeCategory”未完全实现“NSObject”协议

如果我从声明中删除 &lt;SomeDelegate&gt; 可以正常工作,但当然 NSObject 不会被识别为 SomeDelegate

【问题讨论】:

    标签: objective-c cocoa protocols categories


    【解决方案1】:

    一种解决方法是在没有实现的类别上声明协议,并在不同的类别中实现方法,例如:

    @interface NSObject (SomeCategory) <SomeDelegate>
      - (void)someDelegateMessage;    
    @end
    
    @implementation NSObject (SomeCategory_Impl)
      - (void)someDelegateMessage {}
    @end
    

    如果您这样做,NSObject 在编译时将被视为符合&lt;SomeDelegate&gt;,并且someDelegateMessage 的运行时检查将成功。但是,conformsToProtocol: 运行时检查将失败。

    当然,您应该file a bug 要求在核心类上声明的方法不会产生警告。

    【讨论】:

    • 不小心将类别的实现命名为其他东西是代码库最初的样子——纠正它是导致我的问题的原因并引发了这个问题。改回来让我的生活更轻松;虽然我看到这是一个错误的论点,但我认为它是对相当令人讨厌的默认行为的偶然解决方法。 (幸运的是,我的图书馆的任何用户都不需要调用conformsToProtocol:)
    【解决方案2】:

    您的协议声明是否包含NSObject 协议?像这样:

    @protocol SomeDelegate <NSObject>
    ...
    

    这就是警告的来源,因为现在您的类别没有实现完整的协议。在我刚刚输入的测试代码中,从协议中删除 NSObject 会删除编译器警告。

    【讨论】:

    • 是的,这就是我声明SomeDelegate 的方式。但是从中删除&lt;NSObject&gt;——同时删除NSObject(SomeCategory)上的警告——会在每次向委托(作为id&lt;SomeDelegate&gt;)发送NSObject消息时添加新的警告。我不得不想象我还能做些什么来吃蛋糕并在这里吃。
    • 我想不出别的了,抱歉。
    • 不,它不会引起新的警告。 id 接受所有消息而不引起警告,这就是它们的功能。请参阅unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html 了解说明
    • 同意 Louis - 摆脱 NSObject 协议定义,你不需要它。任何 id 变量都可以发送任何消息,而不仅仅是 NSObject 的。
    • 是的,普通的id 变量不会引起警告,但是如果你声明id&lt;SomeDelegate&gt; delegate(贾斯汀想要做的),任何发送到delegate 的NSObject 消息都会引起警告,除非协议声明为@protocol SomeDelegate &lt;NSObject&gt;。第 22 条军规。
    【解决方案3】:

    如果您希望编译器停止发送 消息(重要的是您要记住那是协议名称,而不是类名称),那么只需使用“id”变量,而不是“id”,因为那是你明确告诉编译器“这是一个仅实现 SomeDelegate 协议的对象”。

    或者,使用 NSObject 作为变量类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-31
      • 2018-12-25
      • 2016-11-08
      • 1970-01-01
      相关资源
      最近更新 更多