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
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
- (void)jh_routerWithSelector:(NSString *)selector sender:(id)sender info:(NSDictionary *)info{
NSLog(@"info:%@",info);
//info:{
// xx = name;
//}