Objective-C中的Mixins或多重继承?

ZeN*_*ewb 9 abstract-class objective-c uitextfield uitextview ios

比方说,例如,我有MyUITextViewSubclass从继承UITextViewMyUITextFieldSubclass从中继承UITextField和这两个子类中含有大量的相同的方法和属性类似的行为添加到这些UI控件.

由于UITextViewUITextField从不同的类继承,有一个简单的方法来创建一个抽象类,所有这些重复的代码相结合? 换句话说,是否有可能创建一个我可以从这两个子类继承的抽象类,然后只是覆盖两者之间不同的方法?

到目前为止我所知道的:

  • 我知道Objective-C不支持多继承(从两个或更多类继承)
  • 我知道我可以使用Categories添加常用方法,但我认为这不会解决覆盖init方法或添加私有属性

Joh*_*rug 12

以Amin的答案为基础,您可以这样做:

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

SPWKTextSurrogateHosting.h

#import <Foundation/Foundation.h>

@protocol SPWKTextSurrogateHosting <NSObject>

- (NSString *)text;
- (void)setText:(NSString *)text;

@end
Run Code Online (Sandbox Code Playgroud)

步骤2:创建一个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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

第3步:创建UITextField子类.它将包含三个必要的样板方法,用于将无法识别的方法调用转发给您的SPWKTextSurrogate.

SPWKTextField.h

#import <UIKit/UIKit.h>
#import "SPWKTextSurrogateHosting.h"
#import "SPWKTextSurrogate.h"

@interface SPWKTextField : UITextField <SPWKTextSurrogateHosting, SPWKTextSurrogating>

@end
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

第4步:创建UITextView子类.

SPWKTextView.h

#import <UIKit/UIKit.h>
#import "SPWKTextSurrogateHosting.h"
#import "SPWKTextSurrogate.h"

@interface SPWKTextView : UITextView <SPWKTextSurrogateHosting, SPWKTextSurrogating>

@end
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

第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
Run Code Online (Sandbox Code Playgroud)

这种模式可以解决您的问题.希望 :)

此处提供了更多背景信息:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105