1. 前言
开发中,自定义视图比较复杂,处理事件比较多的时候
需要使用 delegate
或者 block
来回传事件
层级比较多的时候,嵌套也随之增多
结果就是 delegate
嵌套 delegate
或者 block
嵌套 block
一层一层往上传
写着心累,看着心烦
以后要修改或者维护的时候
跳这里,跳那里,跳半天才找到地方
2.正题 - UIResponder
先来一张图:UIResponder及其子类
UIResponder 有一个属性:nextResponder,下一个响应者
利用这个来回传事件
新建分类:
/// UIResponder+JHRouter.h
@interface UIResponder (JHRouter)
- (void)jh_routerWithSelector:(NSString *)selector
sender:(id)sender
info:(NSDictionary *)info;
@end
/// UIResponder+JHRouter.m
#import "UIResponder+JHRouter.h"
@implementation UIResponder (JHRouter)
/*
if an object respondsToSelector: selector
[object respondsToSelector:NSSelectorFromString(selector)]
you should do something.
invoke [super jh_routerWithSelector:selector sender:sender info:info];
Let the events continue to pass up
*/
- (void)jh_routerWithSelector:(NSString *)selector
sender:(id)sender
info:(NSDictionary *)info
{
[[self nextResponder] jh_routerWithSelector:selector
sender:sender
info:info];
}
@end
selector
作为SEL使用时
可以给 NSObject
添加一个分类
然后直接
if ([self respondsToSelector:NSSelectorFromString(selector)]){
[self performSelector:NSSelectorFromString(selector) withObjects:info];
}
// 分类:
@interface NSObject (PerformSelector)
- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects;
@end
#import "NSObject+PerformSelector.h"
@implementation NSObject (PerformSelector)
- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects
{
//
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
//
if (!signature) {
NSString *reason = [NSString stringWithFormat:@"oops~ unrecognized selector %@ sent to instance %@ : %lx",NSStringFromSelector(aSelector),[self class],(unsigned long)[self hash]];
@throw [[NSException alloc] initWithName:@"com.haocold" reason:reason userInfo:nil];
return nil;
}
//
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = aSelector;
// parameters
// first: _cmd
// second: target
NSInteger arguments = signature.numberOfArguments - 2;
//
NSInteger count = MIN(arguments, objects.count);
for (int i = 0; i < count; ++i) {
id obj = objects[i];
if ([obj isKindOfClass:[NSNull class]]) {
obj = nil;
}
[invocation setArgument:&obj atIndex:i+2];
}
//
[invocation invoke];
//
id result = nil;
if (signature.methodReturnLength != 0) {
[invocation getReturnValue:&result];
}
return result;
}
@end
selector
也可以作为一个标志,identifier
if ([selector isEqualToString:@"xxx"]) {
// do something with info.
}
sender
表示触发事件的 view,如果不关注这个,可以传 nil
info
表示要传递的参数,每经过一个 Reaponder
可以加入一些新的参数
view1
添加了 view2
, view2
添加了 view3
view3
内
[self.nextResponder jh_routerWithSelector:@"view3" sender:nil info:nil];
view2
内
- (void)jh_routerWithSelector:(NSString *)selector sender:(id)sender info:(NSDictionary *)info
{
// 给 info 添加一些新的参数
NSMutableDictionary *newInfo = [[NSMutableDictionary alloc] initWithDictionary:info];
[newInfo setObject:@"name" forKey:@"xx"];
[self.nextResponder jh_routerWithSelector:selector sender:sender info:newInfo];
}
view1
内
- (void)jh_routerWithSelector:(NSString *)selector sender:(id)sender info:(NSDictionary *)info{
NSLog(@"info:%@",info);
//info:{
// xx = name;
//}
}
3.注意
当把一个 view
添加到加一个 view
的 window
时,回传事件会被打断!!!