Objective-C中的混合或多重继承? [英] Mixins or Multiple Inheritance in Objective-C?
问题描述
比方说,我有 MyUITextViewSubclass
,它继承自 UITextView
和 MyUITextFieldSubclass
继承自 UITextField
,并且这两个子类都包含许多相同的方法和属性,以向这些UI控件添加类似的行为。
Let's say for example that I have MyUITextViewSubclass
which inherits from UITextView
and MyUITextFieldSubclass
which inherits from UITextField
and both of those subclasses contain a lot of the same methods and properties to add similar behavior to those UI controls.
由于 UITextView
和 UITextField
从不同的类继承,是否容易创建一个抽象类来组合所有重复代码的方法? 换句话说,是否有可能为这两个子类创建一个我可以继承的抽象类,然后只是覆盖两者之间不同的方法?
Since UITextView
and UITextField
inherit from different classes, is there an easy way to create an abstract class to combine all of that repeated code? In other words, is it possible to create an abstract class that I could inherit from for both of those subclasses and then just override the methods that are different between the two?
到目前为止我所知道的:
What I know so far:
- 我知道Objective-C不支持多重继承(从两个继承)或更多类)
- 我知道我可以使用类别添加常用方法,但我认为这不会解决覆盖init方法或添加私有属性
推荐答案
基于Amin的答案,你可以这样做:
Building on Amin's answer, this is how you could do it:
步骤1:创建 TextSurrogateHosting
协议,该协议将包含 UITextField
的所有方法和 UITextView
您需要从要添加到两个子类的方法中访问的子类。例如,这可能是 text
和 setText:
方法,因此您的方法可以访问和设置任一文本文本字段或文本视图。它可能如下所示:
Step 1: Create a TextSurrogateHosting
protocol that will contain all the methods of your UITextField
and UITextView
subclasses that you need to access from the methods that you want to add to both subclasses. This might for example be a text
and setText:
method, so that your methods can access and set the text of either a text field or a text view. It might look like this:
SPWKTextSurrogateHosting.h
SPWKTextSurrogateHosting.h
#import <Foundation/Foundation.h>
@protocol SPWKTextSurrogateHosting <NSObject>
- (NSString *)text;
- (void)setText:(NSString *)text;
@end
第2步:创建一个 TextSurrogate
类,其中包含您要在 UITextField
和 UITextView
子类。将这些方法添加到协议中,以便我们可以在Xcode中使用代码完成并避免编译器警告/错误。
Step 2: Create a TextSurrogate
class that contains all the methods that you want to share between both the UITextField
and the UITextView
subclasses. Add those methods to a protocol so that we can use code completion in Xcode and avoid compiler warnings/errors.
SPWKTextSurrogate.h
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
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步: 创建 UITextField
子类。它将包含三个必要的样板方法,用于将无法识别的方法调用转发到 SPWKTextSurrogate
。
Step 3: Create your UITextField
subclass. It will contain three necessary boilerplate methods to forward unrecognized method invocations to your SPWKTextSurrogate
.
SPWKTextField.h
SPWKTextField.h
#import <UIKit/UIKit.h>
#import "SPWKTextSurrogateHosting.h"
#import "SPWKTextSurrogate.h"
@interface SPWKTextField : UITextField <SPWKTextSurrogateHosting, SPWKTextSurrogating>
@end
SPWKTextField.m
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步: 创建 UITextView
子类。
SPWKTextView.h
SPWKTextView.h
#import <UIKit/UIKit.h>
#import "SPWKTextSurrogateHosting.h"
#import "SPWKTextSurrogate.h"
@interface SPWKTextView : UITextView <SPWKTextSurrogateHosting, SPWKTextSurrogating>
@end
SPWKTextView.m
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
这种模式可以解决你的问题。希望:)
This pattern should solve your problem. Hopefully :)
Some more background information is available here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105
这篇关于Objective-C中的混合或多重继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!