如何在类别中扩展Cocoa协议以避免“在协议中找不到”警告?

时间:2011-06-03 23:38:54

标签: cocoa protocols categories nsoutlineview

这看起来很简单,但我的大脑今天似乎没有工作,而且我的搜索没有得到有用的答案。

我有很多代码通过类别扩展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(及更高版本),以避免“未在协议中找到”警告?

1 个答案:

答案 0 :(得分:0)

我认为这是因为NSOutlineView委托现在输入为id <NSOutlineViewDelegate>而不是普通id,就像在10.5 SDK中一样。该类别在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 <DSOutlineViewDelegate>的对象上调用该方法。您可以通过声明一个为您进行强制转换的新方法来完成此操作,例如:

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

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

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

并且编译器应该没问题。由于该方法在协议中声明为可选方法,因此您仍希望在运行时检查委托是否实际响应选择器。