2012-01-13 20 views
4

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

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

但是,反过来,我想让TextField拥有自己的委托。因此,我创建了一个名为TextFieldDelegate的新协议(注意缺少UI -prefix!),并给予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没有这样的方法。

重写伊娃

我可以尝试声明中PasswordTextField伊娃称为委托,但是编译器会抱怨,这是一个重复的声明,自然是因为已经有所谓的代表在超伊娃,所以这不工作*。

修改超

我能回到TextField类,并重新委托同时实现TextFieldDelegatePasswordTextFieldDelegate,但这似乎凌乱,并告诉TextField,它可以发送PasswordTextFieldDelegate方法,其中当然,它不能!

我没有试过这个,只是因为它似乎打破了书中每一个明智的编码规则。

总之,这样做必须有一些方法,这样一个类的子类可以拥有它自己的委托,它是超类委托的子委托,并且所有这些都可以很好地配合在一起,但是我可以不知道!有任何想法吗?

(*作为一个方面的问题,我不明白为什么编译器会抱怨当PasswordTextField声明了一个“重复”伊娃命名的委托,但是当TextField声明伊娃命名委托这大概是的UITextField重复不抱怨的财产叫代表!)

+0

可能只是打在黑暗中..但不会有帮助,如果你只是重新声明你的委托的@属性为ID ,并有自己的综合?我认为它会奏效。 mebbe生病后试一试 – govi 2012-01-13 14:02:48

回答

1

UITextField委托伊娃被命名_delegate,而不是委托。因此,为什么你不再在TextField中声明它,而是在PasswordTextField中声明它。

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

您可能只需键入代理'id',而不是'id <TextFieldDelegate>'。然后,您可以重写setDelegate并确保委托在conformsToProtocol中传递。但是,您将在此处丢失编译时间检查,只能运行检查conformsToProtocol

+0

感谢澄清_delegate行为。 我确实考虑过只是将类型设置为id--我忘记将它包含在可能的解决方案列表中,但是如您所说,它会丢失编译时检查,所以我会认为会有更好的解决方案? – 2012-01-13 12:57:25

+0

那么你不能拥有两全其美的世界(我不认为你可以....也许有些语言更好).....我来自Java,我错过了强大的类型安全首先。但Objective-C比Java更灵活,我可以忍受这些小怪癖 - 并享受这种语言的所有其他伟大之处。但是,如果我真的不能提供某种类型的东西,我只会使用'id'。 – bandejapaisa 2012-01-26 19:46:01

+0

我可以得到一个代码示例吗? – 2014-04-15 11:50:48

1

因此,那里!工程..和管理有编译时的警告以及..

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 
+1

这工作,直到SimpleChild需要也继承SimpleParent。有没有办法处理它,所以同时继承类和协议的作品? – jowie 2012-09-20 11:49:41

1

这是一个相当混乱的问题,所以请原谅我,如果我错过了这一点,但看起来你的三个不同的继承层次都有不同的要求,每个代表都必须遵守不同的协议,那么这是一个解决方案,将每个级别的代表作为一个不同名称的伊娃,并作为一个不同的参考?

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

基本上,没有规定说委托必须被称为“委托”,所以不要为了不打破它而撕裂自己。

+0

我想象他习惯于其他语言,可以让你做到这一点。例如,在Java中,我可以声明一个实例变量为特定接口(即协议),并且在子类中,我可以重新定义实例变量为更专用的类型(即接口的扩展)。但是,Java是强烈静态类型 – bandejapaisa 2012-01-14 17:10:07

+0

是的,在开发Objective-C之前,我是一名Java开发人员! – 2012-01-26 16:56:15