【问题标题】:Objective-C -- Subclass of delegate in subclassObjective-C——子类中委托的子类
【发布时间】:2012-01-13 11:54:57
【问题描述】:

这是一个相当复杂的继承层次结构,所以请耐心等待(我试图简化事情,而不是说明我正在使用的更复杂的确切情况):-

假设我创建了一个名为TextFieldUITextField 子类,这是我自己的自定义增强型通用文本字段。现在,为了提供这种增强的功能,在TextFieldinit 方法中,我设置了super.delegate = self,以便将来自UITextField 的所有委托方法发送到TextFieldTextField 实现 UITextFieldDelegate 协议并接收这些委托方法来做一些有趣的事情。

然而,反过来,我想让TextField 拥有它的自己的 代表。所以我创建了一个名为TextFieldDelegate 的新协议(注意缺少UI-前缀!)并给TextField 一个具有相应属性的ivar id<TextFieldDelegate> __weak delegate,以便其他类可以从TextField 接收委托方法。

我希望你还在我身边,因为到目前为止我还没有做过任何太复杂的事情。但是假设现在,我创建了TextField 的另一个自定义子类,我们称之为PasswordTextField(在现实生活中,可能不需要创建子类来实现密码功能,但假设有一些相当复杂的实现需要这样做)。

我们还假设我想让PasswordTextField(就像TextField 有一个委托属性)能够发送一组增强的委托方法。例如,也许它可以发送一个方法passwordIsSecure,一旦密码达到所需的复杂程度就会发送该方法。现在,由于这种在常规 TextField 中找不到的行为,我创建了一个新协议:PasswordTextFieldDelegate <TextFieldDelegate>,它为 PasswordTextField 定义了新的委托方法 并且 继承了所有委托方法由TextField发送。

问题是:我如何在PasswordTextField 中实现这个?不起作用的事情:

继承

我不能简单地从TextField 继承委托,因为TextField 的委托只符合TextFieldDelegate 而不是PasswordTextFieldDelegate,所以我不能发送像[delegate passwordIsSecure] 这样的方法,因为TextFieldDelegate 没有这种方法。

覆盖 ivar

我可以尝试在PasswordTextField 中声明一个名为delegate 的ivar,但编译器抱怨这是一个重复的声明,因为当然在超类中已经有一个名为delegate 的ivar,所以这也不起作用*。

修改超类

我可以回到TextField 类并重新定义委托以实现TextFieldDelegate PasswordTextFieldDelegate,但这看起来很混乱,并告诉TextField 它可以发送@987654357 @方法,当然不能!

我没有尝试过这个,只是因为它似乎打破了书中所有合理的编码规则。

总而言之,必须有某种方式来做到这一点,这样一个类的子类可以拥有它自己的委托,它是超类委托的子委托,并且所有这些都可以很好地结合在一起,但我只是可以'想不通!有什么想法吗?

(* 作为一个附带问题,我不明白为什么编译器在PasswordTextField 声明一个名为委托的“重复”ivar 时会抱怨,但是当TextField 声明一个名为委托的 ivar 时编译器不会抱怨,这可能是UITextField 的属性的副本称为委托!)

【问题讨论】:

  • 可能我只是在黑暗中击中.. 但如果您只是将您的代表的@property 重新声明为 id 并拥有自己的合成器,这不会有帮助吗?我认为它会起作用。过段时间我会试一试

标签: iphone objective-c ios oop delegates


【解决方案1】:

UITextField 委托 ivar 被命名为 _delegate,而不是委托。因此,您为什么要在 TextField 中再次声明它而不是在 PasswordTextField 中声明它。

至于您的委托继承问题。我不确定 ObjectiveC 是否支持你想要的。

您可能只需要输入您的委托“id”,而不是“id”。然后您可以覆盖 setDelegate 并确保传入的委托符合符合协议。但是,您将在此处丢失编译时检查,并且只有 conformsToProtocol 的运行时检查

【讨论】:

  • 感谢您澄清 _delegate 行为。我确实考虑过将类型设置为 id - 我忘了将它包含在我的可能解决方案列表中,但正如你所说,它会丢失编译时检查,所以我认为会有更好的解决方案?
  • 嗯,你不能两全其美(好吧,我认为你不能......也许有些语言在这方面做得更好)......我来自Java,起初我错过了强大的 Type 安全性。但是 Objective-C 比 Java 灵活得多,我可以忍受这些小怪癖——并享受这门语言的所有其他优点。但是,如果我真的不能给某样东西一个类型,我只会使用 'id'。
  • 我可以得到一个代码示例吗?
【解决方案2】:

所以,那里!工作..并且设法有编译时警告..

SimpleParent.h

@protocol Parentprotocol <NSObject>

@end

@interface SimpleParent : NSObject {
    id<Parentprotocol> obj;
}

@property (retain) id<Parentprotocol> obj;

@end

SimpleParent.m

#import "SimpleParent.h"

@implementation SimpleParent
@synthesize obj;

@end

SimpleChild.h

#import <Foundation/Foundation.h>
#import "SimpleParent.h"

@protocol SimpleChildProtocol <Parentprotocol>


@end

@interface SimpleChild : NSObject

@property (assign) id<SimpleChildProtocol> obj;

@end

SimpleChild.m

#import "SimpleChild.h"

@implementation SimpleChild
@synthesize obj;

@end

【讨论】:

  • 这行得通,直到 SimpleChild 也需要从 SimpleParent 继承。有没有办法让继承同时从类和协议工作?
【解决方案3】:

这是一个非常令人困惑的问题,如果我遗漏了重点,请原谅我,但是您的三个不同的继承级别似乎每个对他们的委托都有不同的要求,因此每个委托都必须遵守不同的协议,那么将每个级别的代表作为不同命名的 ivar 并作为不同的参考是一种解决方案吗?

例如,您的基类将有其delegate,您已决定将其分配给第一个继承子类。这有它自己的委托,称为level1delegate,下一层有另一个委托,称为level2delegate。如果该对象符合所有三个协议,您当然可以将所有这三个设置为同一个对象。

基本上,没有规定必须将代表称为“代表”,所以不要为了不破坏它而撕裂自己。

【讨论】:

  • 我想他已经习惯了其他允许你这样做的语言。例如,在 Java 中,我可以将实例变量声明为特定接口(即协议),而在子类中,我可以将实例变量重新定义为更专业的类型(即接口的扩展)。然而 Java 是强静态类型的
  • 是的,在使用 Objective-C 进行开发之前,我是一名 Java 开发人员!
猜你喜欢
  • 2011-03-30
  • 2023-03-05
  • 1970-01-01
  • 2010-09-10
  • 1970-01-01
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多