问题描述
假设我有 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?
我目前所知道的:
- 我知道 Objective-C 不支持多重继承(从两个或多个类继承)
- 我知道我可以使用 Categories 添加常用方法,但我认为这不能解决覆盖 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
#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
#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 步: 创建您的 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
#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 步:创建您的 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
这种模式应该可以解决您的问题.希望:)
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 中的混合或多重继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!