【问题标题】:How to extend a Cocoa protocol in a category to avoid "not found in protocol(s)" warning?如何在类别中扩展 Cocoa 协议以避免“未在协议中找到”警告?
【发布时间】:2011-06-03 23:38:54
【问题描述】:

这似乎是一件简单的事情,但我的大脑今天似乎无法正常工作,而且我的搜索也没有找到有用的答案。

我有很多通过类别扩展 Cocoa 类的代码(它也是 open source)。有些方法想调用委托;旧代码使用非正式协议来执行此操作,但现在在构建目标 10.6 时,我收到警告:

warning: '-outlineView:menuForTableColumn:byItem:' not found in protocol(s)

例如,这里有一个类别:

@interface NSOutlineView (DSOutlineViewCategories)

- (NSMenu *)menuForEvent:(NSEvent *)event;

@end

使用非正式协议声明委托方法:

@interface NSObject (DSTableViewDelegate)

- (NSMenu *)outlineView:(NSOutlineView *)olv menuForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;

@end

实现在委托上调用它:

@implementation NSOutlineView (DSOutlineViewCategories)

- (NSMenu *)menuForEvent:(NSEvent *)event
{
    NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
    NSInteger column = [self columnAtPoint:point];
    NSInteger row = [self rowAtPoint:point];
    id item = [self itemAtRow:row];

    if (column >= 0 && item && [[self delegate] respondsToSelector:@selector(outlineView:menuForTableColumn:byItem:)])
        return [[self delegate] outlineView:self menuForTableColumn:[[self tableColumns] objectAtIndex:column] byItem:item];
    else
        return [super menuForEvent:event];
}

@end

如何为 10.6(及更高版本)更新此代码以避免“未在协议中找到”警告?

【问题讨论】:

    标签: cocoa protocols categories nsoutlineview


    【解决方案1】:

    我认为这是因为 NSOutlineView 委托现在键入为 id <NSOutlineViewDelegate>,而不是像在 10.5 SDK 中那样简单的 id。类别在NSObject 上声明,但编译器没有看到委托对象继承自NSObject,因此它无法识别它会响应消息。之前,由于委托是一个普通的id,它不会抱怨发送给它的任何消息,只要它可以在某处找到声明。

    快速而肮脏的解决方法是添加一个演员表,使代码[(id)[self delegate] outlineView:self menuForTableColumn:[[self tableColumns] objectAtIndex:column] byItem:item];

    更正式一点,您可以声明自己的正式委托协议,该协议继承自 NSOutlineViewDelegate,如下所示

    @protocol DSOutlineViewDelegate <NSOutlineViewDelegate>
    
    @optional
    - (NSMenu *)outlineView:(NSOutlineView *)olv menuForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
    
    @end
    

    然后,在调用它的代码中,您可能希望在类型为id &lt;DSOutlineViewDelegate&gt; 的对象上调用该方法。您可以通过声明一个为您进行转换的新方法来做到这一点,例如:

    - (id <DSOutlineViewDelegate>)ds_delegate
    {
        return (id <DSOutlineViewDelegate>)[self delegate];
    }
    

    然后,在实际代码中,您会调用:

    [[self ds_delegate] outlineView:self menuForTableColumn:[[self tableColumns] objectAtIndex:column] byItem:item];
    

    并且编译器应该可以接受。由于该方法在协议中被声明为可选,因此您仍然需要在运行时检查委托是否实际响应了选择器。

    【讨论】:

    • 非常感谢。那确实解决了它。我曾考虑过创建这样的协议,但回避使用演员表;通常是一个红旗。但在这种情况下完全合适。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 2021-01-30
    相关资源
    最近更新 更多