Как расширить протокол Какао в категории, чтобы избежать предупреждения «не найден в протоколе (ах)»? - PullRequest
0 голосов
/ 04 июня 2011

Это кажется простой вещью, но мой мозг, похоже, не работает сегодня, и мои поиски не дали полезного ответа.

У меня есть много кода, который расширяет классы Какао с помощьюкатегории (это с открытым исходным кодом тоже).Некоторые методы хотят вызвать делегата;старый код использовал для этого неформальные протоколы, но теперь при построении таргетинга 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 (и выше), чтобыизбежать предупреждения "not found in protocol (s)"?

1 Ответ

0 голосов
/ 04 июня 2011

Я думаю, это потому, что делегат 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];

и компилятор должен быть в порядке с этим. Поскольку метод объявлен в протоколе как необязательный, вы все равно хотите во время выполнения проверить, действительно ли делегат отвечает на селектор.

...