【问题标题】:Set superclass delegate from subclass setDelegate从子类 setDelegate 设置超类委托
【发布时间】:2015-01-15 21:46:21
【问题描述】:

我有一个超类 A,它有一个 BaseModalViewControllerDelegate 协议和一个 id<BaseModalViewControllerDelegate> delegate 的保留属性。 我还有 B 类,A 的子类,它有一个 ModalLoginDelegate 协议和一个 id<ModalLoginDelegate> delegate 的保留属性

现在,我将这个方法设置为 B 类委托的 setter 方法:

-(void)setDelegate: (id<ModalLoginDelegate>)delegate
{
    _delegate = delegate;
    [super setDelegate: (id<BaseModalViewControllerDelegate>)delegate;
}

所以,有一个 RootViewController 实现了这两个协议,但它只初始化 B 类,并且它只将自己设置为 B 类的委托,因为它不知道 B 类是 A 的子类。

您认为这是将 RootVC 设置为两种协议的委托的正确方法吗?谢谢

添加

将B类的协议设置为继承自A类:

@protocol ModalLoginDelegate <BaseModalDelegate>
    // delegate method of subclass
@end

现在,我的 RootVC 不必将自己设置为 BaseModalViewController 的委托。但是现在,当在我的 B 类中我想调用超类的委托方法时,我正在这样做

if (self.loginDelegate)
{
    [self.loginDelegate baseModalViewController: self willDismiss: YES];
}

我认为这不是一个很干净的方式,所以我在超类-(void)pressedCloseButton; 中创建了一个公共方法,它会这样做

-(void)pressedCloseButton
{
    if (self.delegate)
    {
        [self.delegate baseModalViewController: self willDismiss: YES];
    }
}

在子类中:

-(IBAction)closeBtnPressed: (id)sender
{
    [super pressedCloseButton];
}

你觉得对吗?

【问题讨论】:

  • 如果两个类都有属性delegate,那么只有一个_delegate iVar,所以不需要调用super。您的 A 类应该触发它的委托方法,尽管您应该保护它们以确保委托实现适当的协议
  • 这是正确的,但是,如果没有强制转换委托参数,Xcode 会返回一个关于不同期望 id 的警告。我应该忽略它吗?
  • 更好的设计是为您的子类实现一个单独的委托属性,例如loginDelegate。更改子类中属性的类型并不是很好的 OO 设计。大多数 OO 语言甚至都不允许这样做。这也确保了使用您的类的类“知道”涉及两个独立的委托协议
  • 或者,如果您希望 B 类的委托也始终符合 A 类的委托,您可以使 B 类的委托符合两个协议。例如@property(retain) id&lt;ModalLoginDelegate, BaseModalViewControllerDelegate&gt; delegate;
  • RootVC 如果需要实现这两个协议,则需要将自己设置为两个代表。你不能指望这个类不知道它需要实现哪些委托协议。如果 RootVC 认为它只是在处理基类,那么它不会设置 loginDelegate 并且不会实现该协议中的方法。

标签: ios objective-c inheritance delegates


【解决方案1】:

更好的设计是为您的子类实现一个单独的委托属性,例如loginDelegate。更改子类中属性的类型并不是很好的 OO 设计。大多数 OO 语言甚至都不允许这样做。

这也确保消费类“知道”涉及两个独立的委托协议。

RootVC 如果需要实现两个协议,则需要将自己设置为两个委托。你不能指望这个类不知道它需要实现哪些委托协议。如果RootVC 认为它只是在处理基类,那么它就不会设置 loginDelegate 并且不会实现该协议中的方法。

【讨论】:

    【解决方案2】:

    我完全不同意 Paulw11 的回答,但有趣的是,Apple 自己也这样做了。 例子。 UIScrollView 有一个委托属性

    @property (weak, nonatomic) id <UIScrollViewDelegate> delegate;
    

    一个子类 UITableView 有一个委托属性

    @property (weak, nonatomic) id <UITableViewDelegate> delegate;
    

    当我们在 ObjC 中声明一个协议时,我们通常让该协议扩展 协议。

    @protocol BaseModalViewControllerDelegate <NSObject>
    -(void)doSomething;
    -(NSString *)titleForThing;
    @end
    

    现在上面的这个协议不仅有这里原型化的方法,还有 协议中的方法。它很像这个协议是另一个协议的“子类”,也继承了它的所有东西。

    如果您使用第二个协议进行此操作

      @protocol ModalLoginDelegate <BaseModalViewControllerDelegate>
            -(void)doAnotherThing;
            -(NSString *)titleForTheOtherThing;
        @end
    

    那么你在这里所做的将与 Apple 对 UITableView 和 UIScrollView 所做的完全一致,因为 id 类型的指针始终也是 id 类型的对象,就像 UIButton * 将始终能够作为 UIView* 传入...

    但是如果不这样做,您的

    就会出现根本问题
     -(void)setDelegate:(id<ModalLoginDelegate>)delegate
    

    方法,因为您假设此对象符合 BaseModalViewControllerDelegate 协议,而您唯一确定的是它符合 ModalLoginDelegate 协议。某些继承的方法可能会使用 self.delegate 不响应的 BaseModalViewControllerDelegate 方法调用 self.delegate。 我希望这会有所帮助:)

    【讨论】:

    • 嗨,杰夫,我尝试了您的解决方案,现在我的 RootVC 没有将自己设置为 BaseModalViewController 的代表,但是,正如 @Paulw11 所说,我认为如果我将 RootVC 设置为BaseModalVC 委托。它实现了协议,所以它知道这个类,那么我为什么要隐藏它的委托属性呢?
    • 现在,我不知道,但ModalLoginViewController 它执行这样的操作:-(IBAction)closeBtnPressed:(id)sender { if (self.loginDelegate &amp;&amp; [self.loginDelegate respondsToSelector: @selector(baseModalViewController:willDismiss:)]) { [self.loginDelegate baseModalViewController: self willDismiss: YES]; } } 我认为这不是一个干净的方法。也许我必须在超类中设置一个公共方法并从子类中调用它。然后超类调用它的委托...
    • 哦,伙计,我并不是真的建议你这样做(用协议 2 扩展协议 1),除非它对你的设计真的有意义。就像保罗说的那样做,但是给第二个代表打电话,也许是 self.loginDelegate 我只是觉得它很有趣,并且在某些情况下适用于你的问题(例如 UIScrollView、UITableView )
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多