在Amin的回答基础上,您可以按照以下步骤进行操作:
第1步:创建一个TextSurrogateHosting
协议,其中包含您需要从要添加到两个子类中的方法访问的UITextField
和UITextView
子类的所有方法。例如,这可能是一个text
和setText:
方法,以便您的方法可以访问并设置文本字段或文本视图的文本。它可能看起来像这样:
SPWKTextSurrogateHosting.h
#import <Foundation/Foundation.h>
@protocol SPWKTextSurrogateHosting <NSObject>
- (NSString *)text;
- (void)setText:(NSString *)text;
@end
第二步: 创建一个 TextSurrogate
类,其中包含您想在 UITextField
和 UITextView
子类之间共享的所有方法。将这些方法添加到协议中,以便我们可以在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
第三步:创建你的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
第四步:创建你的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
这个模式应该能解决你的问题。希望如此 :)
[myUITextViewSubclass.helper doSomething]
替代
[myUITextViewSubclass doSomething]
Objective-C不支持Traits或Mixins,你只有内置的分类选项。
但幸运的是,Objective-C Runtime几乎拥有所有工具来实现自己的混合或特性想法,通过在运行时向类添加方法和属性。您可以在苹果文档网站Objective-C Runtime Docs上了解更多Objective-C Runtime为您提供的机会。
思路如下:
1)您可以创建一个Objective-C协议(Mixin),其中您将声明属性和方法。
2)然后创建一个类(Mixin实现),该类将实现此协议中的方法。
3)使您希望提供与mixins组合的可能性的某些类符合该协议(Mixin)。
4)当您的应用程序启动时,您使用Objective-C runtime将(Mixin实现)类中的所有实现以及(Mixin)中声明的属性添加到您的类中。
5)完成 :)
或者您可以使用一些现成的开源项目,例如“Alchemiq”
不,这是不可能的。
你能做到的最接近的事情就是手动添加功能到UITextView
,使其模仿UITextField
。显而易见的缺点是你必须手动完成所有这些工作,使用自己的代码。
你可以使用预处理器宏,但这样容易出错。