【问题标题】:How to implement delegation the right way?如何正确实施委托?
【发布时间】:2010-11-16 10:16:20
【问题描述】:

我正在尝试为一个应该称为委托(如果有的话)的类实现委托,当特殊情况发生时。

来自维基百科我有这个代码示例:

 @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 中的警告。有更好的模式吗?

【问题讨论】:

  • 您不必在 Objective-c 中检查 nil。向 nil 对象发送消息是合法的。
  • 在这种情况下,您不需要检查 nil,因为 BOOL 小于 sizeof(void*)。然而,对于任何其他大小的返回类型——比如说,一个大型结构——返回值是未定义的,因此,检查 nil 是防止未定义行为的唯一方法。

标签: iphone delegation


【解决方案1】:

您可以让委托是实现 SomeClassDelegate 协议的 id 类型。为此,您可以在 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

【讨论】:

    【解决方案2】:

    跟进drvdijk's answer 中的示例代码,如果在调用委托方法时delegate 有可能成为nil,则可能会出现问题。

    发送到nil 的消息的返回值为nil(又名0.0 又名0 又名NO),所以如果delegatenil

    [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
    

    【讨论】:

      【解决方案3】:

      使用[NSObject performSelector:]

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

      您不会再收到编译器警告。

      或者创建一个协议并在头文件中声明MyProtocol *delegate

      【讨论】:

        猜你喜欢
        • 2011-05-13
        • 1970-01-01
        • 2013-11-26
        • 2013-12-20
        • 1970-01-01
        • 1970-01-01
        • 2019-02-01
        • 1970-01-01
        • 2022-12-22
        相关资源
        最近更新 更多