Objective-C中的Mixins或Multiple Inheritance

比方说,我有MyUITextViewSubclassinheritance自UITextViewMyUITextFieldSubclassUITextFieldinheritance,这两个子类包含很多相同的方法和属性添加到这些UI控件的相似的行为。

由于UITextViewUITextField从不同的类inheritance,是否有一种简单的方法来创build一个抽象类来组合所有重复的代码? 换句话说,是否有可能为这两个子类创build一个可以inheritance的抽象类,然后重写两者之间不同的方法?

到目前为止我所知道的是:

  • 我知道Objective-C不支持多重inheritance(从两个或更多的类inheritance)
  • 我知道我可以使用类别添加通用的方法,但我不认为这解决了重写init方法或添加私有属性

build立在阿敏的答案,这是你如何做到这一点:

第1步:创build一个TextSurrogateHosting协议,该协议将包含您需要从要添加到两个子类中的方法访问的UITextFieldUITextView子类的所有方法。 例如,这可能是一个textsetText:方法,以便您的方法可以访问和设置文本字段或文本视图的文本。 它可能看起来像这样:

SPWKTextSurrogateHosting.h

 #import <Foundation/Foundation.h> @protocol SPWKTextSurrogateHosting <NSObject> - (NSString *)text; - (void)setText:(NSString *)text; @end 

第2步:创build一个TextSurrogate类,其中包含您要在UITextFieldUITextView子类之间共享的所有方法。 将这些方法添加到协议中,以便我们可以在Xcode中使用代码完成,并避免编译器警告/错误。

SPWKTextSurrogate.h

 #import <Foundation/Foundation.h> #import "SPWKTextSurrogateHosting.h" @protocol SPWKTextSurrogating <NSObject> @optional - (void)appendQuestionMark; - (void)appendWord:(NSString *)aWord; - (NSInteger)characterCount; - (void)capitalize; @end @interface SPWKTextSurrogate : NSObject <SPWKTextSurrogating> /* We need to init with a "host", either a UITextField or UITextView subclass */ - (id)initWithHost:(id<SPWKTextSurrogateHosting>)aHost; @end 

SPWKTextSurrogate.m

 #import "SPWKTextSurrogate.h" @implementation SPWKTextSurrogate { id<SPWKTextSurrogateHosting> _host; } - (id)initWithHost:(id<SPWKTextSurrogateHosting>)aHost { self = [super init]; if (self) { _host = aHost; } return self; } - (void)appendQuestionMark { _host.text = [_host.text stringByAppendingString:@"?"]; } - (void)appendWord:(NSString *)aWord { _host.text = [NSString stringWithFormat:@"%@ %@", _host.text, aWord]; } - (NSInteger)characterCount { return [_host.text length]; } - (void)capitalize { _host.text = [_host.text capitalizedString]; } @end 

第3步:创build您的UITextField子类。 它将包含三个必要的样板方法,用于将未识别的方法调用转发到SPWKTextSurrogate

SPWKTextField.h

 #import <UIKit/UIKit.h> #import "SPWKTextSurrogateHosting.h" #import "SPWKTextSurrogate.h" @interface SPWKTextField : UITextField <SPWKTextSurrogateHosting, SPWKTextSurrogating> @end 

SPWKTextField.m

 #import "SPWKTextField.h" @implementation SPWKTextField { SPWKTextSurrogate *_surrogate; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _surrogate = [[SPWKTextSurrogate alloc] initWithHost:self]; } return self; } #pragma mark Invocation Forwarding - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([_surrogate respondsToSelector:[anInvocation selector]]) { [anInvocation invokeWithTarget:_surrogate]; } else { [super forwardInvocation:anInvocation]; } } - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector { NSMethodSignature* signature = [super methodSignatureForSelector:selector]; if (!signature) { signature = [_surrogate methodSignatureForSelector:selector]; } return signature; } - (BOOL)respondsToSelector:(SEL)aSelector { if ([super respondsToSelector:aSelector] || [_surrogate respondsToSelector:aSelector]) { return YES; } return NO; } @end 

第4步:创build你的UITextView子类。

SPWKTextView.h

 #import <UIKit/UIKit.h> #import "SPWKTextSurrogateHosting.h" #import "SPWKTextSurrogate.h" @interface SPWKTextView : UITextView <SPWKTextSurrogateHosting, SPWKTextSurrogating> @end 

SPWKTextView.m

 #import "SPWKTextView.h" #import "SPWKTextSurrogate.h" @implementation SPWKTextView { SPWKTextSurrogate *_surrogate; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _surrogate = [[SPWKTextSurrogate alloc] initWithHost:self]; } return self; } #pragma mark Invocation Forwarding - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([_surrogate respondsToSelector:[anInvocation selector]]) { [anInvocation invokeWithTarget:_surrogate]; } else { [super forwardInvocation:anInvocation]; } } - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector { NSMethodSignature* signature = [super methodSignatureForSelector:selector]; if (!signature) { signature = [_surrogate methodSignatureForSelector:selector]; } return signature; } - (BOOL)respondsToSelector:(SEL)aSelector { if ([super respondsToSelector:aSelector] || [_surrogate respondsToSelector:aSelector]) { return YES; } return NO; } @end 

第5步:使用它:

 SPWKTextField *textField = [[SPWKTextField alloc] initWithFrame:CGRectZero]; SPWKTextView *textView = [[SPWKTextView alloc] initWithFrame:CGRectZero]; textField.text = @"The green fields"; textView.text = @"What a wonderful view"; [textField capitalize]; [textField appendWord:@"are"]; [textField appendWord:@"green"]; [textField appendQuestionMark]; NSLog(@"textField.text: %@", textField.text); // Output: The Green Fields are green? [textView capitalize]; [textView appendWord:@"this"]; [textView appendWord:@"is"]; NSLog(@"textView.text: %@", textView.text); // Output: What A Wonderful View this is 

这种模式应该能解决你的问题。 希望 :)

更多的背景信息可以在这里find: https : //developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105

你想要的是一个混合。 Objective-C不支持这个function。 分类是没有混入,因为他们添加到一个类的api不是很多 (> 1)类。 使用类别,如你所说,有许多原因是不可能的,不会帮助你。

解决这个问题的常用方法是创build一个包含附加代码的助手类,并在两个类中使用它。

然后你会发现自己打字

 [myUITextViewSubclass.helper doSomething] 

代替

 [myUITextViewSubclass doSomething] 

如果这真的是一个问题,你可以用forward调用来解决这个问题。 只要写评论。

不,这是不可能的。

您可以实现的最接近的function是手动添加function到UITextView使其模仿UITextField 。 显而易见的缺点是,你必须手动完成这一切,用自己的代码。

你可以使用预处理macros,但是这是很容易出错的。

Objective-C不支持Traits或Mixins,只有内置的类别选项。 幸运的是,Objective-C Runtime几乎包含了所有用于实现自己的想法的工具,如果混合或者在运行时为你的类添加方法和属性。 您可以在Apple的文档网站Objective-C Runtime Docs上阅读更多关于Objective-C Runtime为您提供的机会

这个想法是:

1)您可以创build一个Objective-C协议(Mixin),在其中您将声明属性和方法。

2)然后你创build一个类(Mixin实现),它将实现这个协议的方法。

3)你让你想要提供与mixin组合的可能性的类,以符合该协议(Mixin)。

4)当你的应用程序启动时,你将(Mixin实现)类和(Mixin)中声明的属性的所有实现添加到Objective-C运行时到你的类中。

5)voilà:)

或者你可以使用一些现成的开源项目,比如“ Alchemiq ”

Interesting Posts