1. 前言
開(kāi)發(fā)中,自定義視圖比較復(fù)雜迁杨,處理事件比較多的時(shí)候
需要使用 delegate
或者 block
來(lái)回傳事件
層級(jí)比較多的時(shí)候,嵌套也隨之增多
結(jié)果就是 delegate
嵌套 delegate
或者 block
嵌套 block
一層一層往上傳
寫(xiě)著心累伶选,看著心煩
以后要修改或者維護(hù)的時(shí)候
跳這里词渤,跳那里,跳半天才找到地方
2.正題 - UIResponder
先來(lái)一張圖:UIResponder及其子類(lèi)
UIResponder及其子類(lèi)
UIResponder 有一個(gè)屬性:nextResponder喧务,下一個(gè)響應(yīng)者
利用這個(gè)來(lái)回傳事件
新建分類(lèi):
/// 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使用時(shí)
可以給 NSObject
添加一個(gè)分類(lèi)
然后直接
if ([self respondsToSelector:NSSelectorFromString(selector)]){
[self performSelector:NSSelectorFromString(selector) withObjects:info];
}
// 分類(lèi):
@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
也可以作為一個(gè)標(biāo)志赖歌,identifier
if ([selector isEqualToString:@"xxx"]) {
// do something with info.
}
sender
表示觸發(fā)事件的 view,如果不關(guān)注這個(gè)功茴,可以傳 nil
info
表示要傳遞的參數(shù)庐冯,每經(jīng)過(guò)一個(gè) Reaponder
可以加入一些新的參數(shù)
view1
添加了 view2
, view2
添加了 view3
view3
內(nèi)
[self.nextResponder jh_routerWithSelector:@"view3" sender:nil info:nil];
view2
內(nèi)
- (void)jh_routerWithSelector:(NSString *)selector sender:(id)sender info:(NSDictionary *)info
{
// 給 info 添加一些新的參數(shù)
NSMutableDictionary *newInfo = [[NSMutableDictionary alloc] initWithDictionary:info];
[newInfo setObject:@"name" forKey:@"xx"];
[self.nextResponder jh_routerWithSelector:selector sender:sender info:newInfo];
}
view1
內(nèi)
- (void)jh_routerWithSelector:(NSString *)selector sender:(id)sender info:(NSDictionary *)info{
NSLog(@"info:%@",info);
//info:{
// xx = name;
//}
}
3.注意
當(dāng)把一個(gè) view
添加到加一個(gè) view
的 window
時(shí),回傳事件會(huì)被打斷?泊U垢浮返劲!