Как правильно осуществить делегирование? - PullRequest
1 голос
/ 03 августа 2009

Я пытаюсь реализовать делегирование для класса, который должен вызывать его делегат (если есть), когда происходят особые события.

Из Википедии у меня есть пример кода:

 @implementation TCScrollView
 -(void)scrollToPoint:(NSPoint)to;
 {
   BOOL shouldScroll = YES;
   // If we have a delegate, and that delegate indeed does implement our delegate method,
   if(delegate && [delegate respondsToSelector:@selector(scrollView:shouldScrollToPoint:)])
     shouldScroll = [delegate scrollView:self shouldScrollToPoint:to]; // ask it if it's okay to scroll to this point.

   if(!shouldScroll) return;  // If not, ignore the scroll request.

   /// Scrolling code omitted.
 }
 @end

Если я попытаюсь сделать это самостоятельно, я получу предупреждение о том, что метод, который я вызываю для делегата, не найден. Конечно, это не так, потому что на делегата ссылается только id. Это может быть что угодно. Конечно, во время выполнения это будет работать нормально, потому что я проверяю, отвечает ли он на селектор. Но я не хочу предупреждение в Xcode. Есть ли лучшие образцы?

Ответы [ 3 ]

7 голосов
/ 03 августа 2009

Вы можете разрешить делегату принадлежать к типу id, который реализует протокол SomeClassDelegate. Для этого вы можете в заголовке вашего SomeClass (в вашем случае TCScrollView) сделать что-то вроде этого:

@protocol TCScrollViewDelegate; // forward declaration of the protocol

@interface TCScrollView {
    // ...
    id <TCScrollViewDelegate> delegate;
}
@property (assign) id<TCScrollViewDelegate> delegate;
@end

@protocol TCScrollViewDelegate
- (BOOL) scrollView:(TCScrollView *)tcScrollView shouldScrollToPoint:(CGPoint)to;
@end

Тогда вы можете из своей реализации просто вызвать метод делегата:

@implementation TCScrollView

-(void)scrollToPoint:(NSPoint)to;
{
  BOOL shouldScroll = YES;
  shouldScroll = [delegate scrollView:self shouldScrollToPoint:to]; // ask it if it's okay to scroll to this point.
  if(!shouldScroll) return;  // If not, ignore the scroll request.
  /// Scrolling code omitted.
}
@end
0 голосов
/ 27 октября 2009

Использование [NSObject performSelector:]

[delegate performSelector:@selector(scrollView:shouldScrollToPoint:) withObject:self withObject:to];

Вы больше не будете получать предупреждения компилятора.

Либо создайте протокол и объявите MyProtocol *delegate в заголовочном файле.

0 голосов
/ 27 октября 2009

Следуя примеру кода в ответе drvdijk , может возникнуть проблема, если есть вероятность, что delegate может быть nil при вызове метода делегата.

Возвращаемое значение сообщения, отправленного на nil, равно nil (он же 0.0 он же 0 он же NO), поэтому, если delegate равно nil,

[delegate scrollView:self shouldScrollToPoint:to]

вернет NO, что может быть нежелательным поведением в вашем случае. Сначала безопаснее проверить:

if (delegate != nil) {
    shouldScroll = [delegate scrollView:self shouldScrollToPoint:to]
}

Кроме того, если вы не хотите видеть предупреждение компилятора при отправке сообщений, объявленных NSObject вашему делегату (например, respondsToSelector:), включите протокол NSObject в объявление протокола:

@protocol TScrollViewDelegate <NSObject>
- (BOOL) scrollView:(TCScrollView *)tcScrollView shouldScrollToPoint:(CGPoint)to;
@end
...