在工作的过程中,我们经常会遇到一些需求是这样的:限制textField的输入字数上限,且只允许输入数字;反复使用同样代码的delegate方法;以及delegate方法实现的内容相同但是代码不统一,等等。这样很影响工作的效率,因为只能凭着自己写过的记忆去寻找某个delegate的实现方法。于是我就开始思考如何整理常用的delegate方法的实现。
用一个常用的具体例子来思考处理的办法,比如:UITextField需要限制输入字符的长度,且需要不能输入emoji表情。

这个时候又想到了可能Method1可能在某些业务场景下,要放在Method2之后。那没问题,可以再textField的子类中再加一个属性控制。然后继续思考,可能delegate方法需要在业务层里面有入口,那就继续在子类中再加上will和end两个回调。

到了这里,我感觉就略显尴尬了,因为有些时候Method1和Method2之间,也可能业务层需要有操作,如果继续添加回调就会太过于臃肿,并且如果后面还有Method3,4,5,那么这个子类可能会越来越难以维护。
所以,回到问题的原点,可不可以将需要组件化的method一个一个的封装起来呢?但是这样做的话,由于OC只能单delegate的问题,我们还需要实现一个可以多重代理的center,去转发消息给消息接收者handler,然后handler再自己处理需要实现的method。这样可以很好的完成我们的目标,且降低代码耦合度。

直接上center的代码
center.h
@interface RCYMultableDelegateTransmitCenter : NSObject
- (void)addTransmitDelegates:(NSArray<id> *)delegates;
- (void)insertTransmitDelegates:(NSArray<id> *)delegates index:(NSUInteger)index;
- (void)updateTransmitDelegates;
- (void)removeTransitDelegateAtIndex:(NSInteger)index;
- (void)removeAllTransmitDelegates;
- (NSArray<id> *)AllDelegates;
@end
center.m
#import "RCYMultableDelegateTransmitCenter.h"
@interface RCYMultableDelegateTransmitCenter ()
@property (nonatomic, strong) NSPointerArray *delegatePointerArray;
@end
@implementation RCYMultableDelegateTransmitCenter
#pragma mark - publish
- (void)addTransmitDelegates:(NSArray<id> *)delegates {
for (id delegate in delegates) {
[self.delegatePointerArray addPointer:(__bridge void *)delegate];
}
}
- (void)insertTransmitDelegates:(NSArray<id> *)delegates index:(NSUInteger)index {
if (index > self.delegatePointerArray.count - 1 || !self.delegatePointerArray.count) {
[self addTransmitDelegates:delegates];
return;
}
for (int i = 0; i < delegates.count; i++) {
[self.delegatePointerArray insertPointer:(__bridge void *)(delegates[i]) atIndex:index + i];
}
}
- (void)updateTransmitDelegates {
[self.delegatePointerArray addPointer:NULL];
[self.delegatePointerArray compact];
}
- (void)removeTransitDelegateAtIndex:(NSInteger)index {
if (self.delegatePointerArray.count > index) {
[self.delegatePointerArray removePointerAtIndex:index];
[self updateTransmitDelegates];
}
}
- (void)removeAllTransmitDelegates {
self.delegatePointerArray = [NSPointerArray weakObjectsPointerArray];
}
- (NSArray<id> *)AllDelegates {
return self.delegatePointerArray.allObjects;
}
#pragma mark - private
- (BOOL)respondsToSelector:(SEL)aSelector{
if ([super respondsToSelector:aSelector]) {
return YES;
}
for (id target in self.delegatePointerArray) {
if ([target respondsToSelector:aSelector]) {
return YES;
}
}
return NO;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *sig = [super methodSignatureForSelector:aSelector];
if (!sig) {
for (id target in self.delegatePointerArray) {
if ((sig = [target methodSignatureForSelector:aSelector])) {
break;
}
}
}
return sig;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
for (id target in self.delegatePointerArray) {
if ([target respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:target];
}
}
}
#pragma mark - getter
- (NSPointerArray *)delegatePointerArray {
if (!_delegatePointerArray) {
_delegatePointerArray = [NSPointerArray weakObjectsPointerArray];
}
return _delegatePointerArray;
}
可以看到,center通过消息转发,实现了将delegate转发给NSPointerArray里面的对象,于是我们可以通过创建实现<UITextFieldDelegate>的不同Object,来处理不同的业务需要。
这里贴一个限制textView输入的代码,具体Demo请看这里,目前只实现了textField和textView的限制输入方法。
@interface ViewController ()<UITextViewDelegate>
@property (nonatomic, strong) UITextView *textView;
@property (nonatomic, strong) RCYTextViewLimitLengthHandler *textViewLimitLengthHandler;
@property (nonatomic, strong) RCYTextViewLimitCharacterHandler *textViewLimitCharHandler;
@property (nonatomic, strong) RCYMultableDelegateTransmitCenter *textViewCenter;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textView = [[UITextView alloc] init];
self.textView.frame = CGRectMake(0, 30, 200, 50);
self.textView.backgroundColor = UIColor.redColor;
[self.view addSubview:self.textView];
self.textViewLimitLengthHandler = [[RCYTextViewLimitLengthHandler alloc] init];
self.textViewLimitLengthHandler.maxLimit = 5;
self.textViewLimitLengthHandler.maxLimitBlock = ^{
NSLog(@"已经输入了5个字了");
};
self.textViewLimitCharHandler = [[RCYTextViewLimitCharacterHandler alloc] init];
self.textViewLimitCharHandler.state = RCYLimitCharacterStateChinese | RCYLimitCharacterStateEmoji;//禁止输入汉字/表情
self.textViewLimitCharHandler.limitBlock = ^{
NSLog(@"view输入不可描述内容");
};
self.textViewCenter = [[RCYMultableDelegateTransmitCenter alloc] init];
//这里,业务层的self也可以作为handler传给center
[self.textViewCenter addTransmitDelegates:@[self.textViewLimitLengthHandler, self, self.textViewLimitCharHandler]];
self.textView.delegate = (id<UITextViewDelegate>)self.textViewCenter;
UIButton *removeLimitButton = [[UIButton alloc] init];
[removeLimitButton setTitle:@"取消限制" forState:UIControlStateNormal];
[removeLimitButton setTitleColor:UIColor.redColor forState:UIControlStateNormal];
removeLimitButton.frame = CGRectMake(200, 30, 120, 50);
[removeLimitButton addTarget:self action:@selector(removeAllLimit) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:removeLimitButton];
UIButton *addLimitButton = [[UIButton alloc] init];
[addLimitButton setTitle:@"添加限制" forState:UIControlStateNormal];
[addLimitButton setTitleColor:UIColor.redColor forState:UIControlStateNormal];
addLimitButton.frame = CGRectMake(200, 100, 120, 50);
[addLimitButton addTarget:self action:@selector(addAllLimit) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:addLimitButton];
}
- (void)removeAllLimit {
//两种方式都可以
// self.textViewLimitLengthHandler = nil;
// [self.textViewCenter updateTransmitDelegates];
[self.textViewCenter removeTransitDelegateAtIndex:0];
NSLog(@"移除了限制");
}
- (void)addAllLimit {
[self.textViewCenter addTransmitDelegates:@[self.textViewLimitLengthHandler]];
NSLog(@"添加了限制");
}
- (void)textViewDidChange:(UITextView *)textView {
NSLog(@"改变了");
}
@end
网友评论